/*
 * This file is part of roccat-tools.
 *
 * roccat-tools 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.
 *
 * roccat-tools 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with roccat-tools. If not, see <http://www.gnu.org/licenses/>.
 */

#include "roccat_macro_editor_basic_tree_view.h"

#define ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW_TYPE, RoccatMacroEditorBasicTreeViewClass))
#define IS_ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW_TYPE))
#define ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW_TYPE, RoccatMacroEditorBasicTreeViewPrivate))

typedef struct _RoccatMacroEditorBasicTreeViewClass RoccatMacroEditorBasicTreeViewClass;

struct _RoccatMacroEditorBasicTreeViewClass {
	GtkTreeViewClass parent_class;
};

struct _RoccatMacroEditorBasicTreeViewPrivate {
	GtkMenu *menu;
};

G_DEFINE_TYPE(RoccatMacroEditorBasicTreeView, roccat_macro_editor_basic_tree_view, GTK_TYPE_TREE_VIEW);

static gchar const * const macro_list_key_key = "macro_list_key";

void roccat_macro_editor_basic_tree_view_add_keystroke(RoccatMacroEditorBasicTreeView *tree_view, guint key, guint action, glong rel_time) {
	GtkTreeSelection *selection;
	GtkTreeModel *model;
	GtkTreeIter insert_iter;
	GtkTreeIter *pinsert_iter;

	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
	if (gtk_tree_selection_get_selected(selection, &model, &insert_iter)) {
		pinsert_iter = &insert_iter;
	} else {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view));
		pinsert_iter = NULL;
	}

	roccat_macro_editor_basic_list_store_insert_keystroke_before(ROCCAT_MACRO_EDITOR_BASIC_LIST_STORE(model), pinsert_iter, key, action, rel_time);
}

static void popup_insert_delay_cb(GtkMenuItem *item, gpointer user_data) {
	RoccatMacroEditorBasicTreeView *tree_view = ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW(user_data);
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTreeIter insert_iter;
	GtkTreeIter *pinsert_iter;

	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
	if (gtk_tree_selection_get_selected(selection, &model, &insert_iter)) {
		pinsert_iter = &insert_iter;
	} else {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view));
		pinsert_iter = NULL;
	}

	roccat_macro_editor_basic_list_store_insert_period_before(ROCCAT_MACRO_EDITOR_BASIC_LIST_STORE(model), pinsert_iter, 1);
}

static void popup_insert_button_down_cb(GtkMenuItem *item, gpointer user_data) {
	RoccatMacroEditorBasicTreeView *tree_view = ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW(user_data);
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTreeIter insert_iter;
	GtkTreeIter *pinsert_iter;
	guint key;

	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
	if (gtk_tree_selection_get_selected(selection, &model, &insert_iter)) {
		pinsert_iter = &insert_iter;
	} else {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view));
		pinsert_iter = NULL;
	}

	key = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(item), macro_list_key_key));

	roccat_macro_editor_basic_list_store_insert_single_action_key_before(ROCCAT_MACRO_EDITOR_BASIC_LIST_STORE(model),
			pinsert_iter, key, ROCCAT_MACRO_KEYSTROKE_ACTION_PRESS);
}

static void popup_insert_button_up_cb(GtkMenuItem *item, gpointer user_data) {
	RoccatMacroEditorBasicTreeView *tree_view = ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW(user_data);
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTreeIter insert_iter;
	GtkTreeIter *pinsert_iter;
	guint key;

	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
	if (gtk_tree_selection_get_selected(selection, &model, &insert_iter)) {
		pinsert_iter = &insert_iter;
	} else {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view));
		pinsert_iter = NULL;
	}

	key = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(item), macro_list_key_key));

	roccat_macro_editor_basic_list_store_insert_single_action_key_before(ROCCAT_MACRO_EDITOR_BASIC_LIST_STORE(model),
			pinsert_iter, key, ROCCAT_MACRO_KEYSTROKE_ACTION_RELEASE);
}

static void popup_insert_button_click_cb(GtkMenuItem *item, gpointer user_data) {
	RoccatMacroEditorBasicTreeView *tree_view = ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW(user_data);
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTreeIter insert_iter;
	GtkTreeIter *pinsert_iter;
	guint key;

	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
	if (gtk_tree_selection_get_selected(selection, &model, &insert_iter)) {
		pinsert_iter = &insert_iter;
	} else {
		model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view));
		pinsert_iter = NULL;
	}

	key = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(item), macro_list_key_key));

	roccat_macro_editor_basic_list_store_insert_dual_action_key_before(ROCCAT_MACRO_EDITOR_BASIC_LIST_STORE(model), pinsert_iter, key);
}

static void popup_remove_cb(GtkMenuItem *item, gpointer user_data) {
	RoccatMacroEditorBasicTreeView *tree_view = ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW(user_data);
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTreeIter entry;

	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
	/* object to be removed has to be selected */
	if (!gtk_tree_selection_get_selected(selection, &model, &entry))
		return;

	roccat_macro_editor_basic_list_store_remove(ROCCAT_MACRO_EDITOR_BASIC_LIST_STORE(model), &entry);
}

static GtkWidget *subsubmenu(RoccatMacroEditorBasicTreeView *tree_view, guint key) {
	GtkWidget *menu, *item;

	menu = gtk_menu_new();

	item = gtk_menu_item_new_with_label("Down");
	g_object_set_data(G_OBJECT(item), macro_list_key_key, GUINT_TO_POINTER(key));
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(popup_insert_button_down_cb), tree_view);

	item = gtk_menu_item_new_with_label("Up");
	g_object_set_data(G_OBJECT(item), macro_list_key_key, GUINT_TO_POINTER(key));
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(popup_insert_button_up_cb), tree_view);

	item = gtk_menu_item_new_with_label("Click");
	g_object_set_data(G_OBJECT(item), macro_list_key_key, GUINT_TO_POINTER(key));
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(popup_insert_button_click_cb), tree_view);

	return menu;
}

static GtkWidget *submenu(RoccatMacroEditorBasicTreeView *tree_view) {
	GtkWidget *menu, *item;

	menu = gtk_menu_new();

	item = gtk_menu_item_new_with_label("Left button");
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), subsubmenu(tree_view, ROCCAT_MACRO_KEYSTROKE_KEY_BUTTON_LEFT));

	item = gtk_menu_item_new_with_label("Right button");
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), subsubmenu(tree_view, ROCCAT_MACRO_KEYSTROKE_KEY_BUTTON_RIGHT));

	item = gtk_menu_item_new_with_label("Middle button");
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), subsubmenu(tree_view, ROCCAT_MACRO_KEYSTROKE_KEY_BUTTON_MIDDLE));

	return menu;
}

static GtkWidget *menu_new(RoccatMacroEditorBasicTreeView *tree_view) {
	GtkWidget *menu, *item;

	menu = gtk_menu_new();

	item = gtk_image_menu_item_new_from_stock(GTK_STOCK_REMOVE, NULL);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(popup_remove_cb), tree_view);

	item = gtk_menu_item_new_with_label("Insert delay");
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(popup_insert_delay_cb), tree_view);

	item = gtk_menu_item_new_with_label("Insert mouse event");
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu(tree_view));

	gtk_widget_show_all(menu);
	return menu;
}

static void delay_edited_cb(GtkCellRendererText *renderer, gchar const *path_string, gchar const *new_text, gpointer user_data) {
	RoccatMacroEditorBasicTreeView *tree_view = ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW(user_data);
	RoccatMacroEditorBasicListStore *store;
	GtkTreePath *path;
	GtkTreeIter iter;

	store = ROCCAT_MACRO_EDITOR_BASIC_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)));
	path = gtk_tree_path_new_from_string(path_string);
	gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path);
	roccat_macro_editor_basic_list_store_set_value(store, &iter, new_text);
	gtk_tree_path_free(path);
}

GtkWidget *roccat_macro_editor_basic_tree_view_new(RoccatMacroEditorBasicListStore *list_store) {
	RoccatMacroEditorBasicTreeView *tree_view;

	tree_view = g_object_new(ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW_TYPE,
			NULL);

	gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view), GTK_TREE_MODEL(list_store));

	return GTK_WIDGET(tree_view);
}

static gboolean popup_menu_on_right_mouse_button_cb(GtkTreeView *tree_view, GdkEventButton *event, gpointer user_data) {
	RoccatMacroEditorBasicTreeViewPrivate *priv = ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW(tree_view)->priv;

	if (!(event->type == GDK_BUTTON_PRESS && event->button == 3))
		return FALSE;

	gtk_menu_popup(GTK_MENU(priv->menu), NULL, NULL, NULL, NULL, event->button, gdk_event_get_time((GdkEvent*)event));

	return TRUE;
}

static void roccat_macro_editor_basic_tree_view_init(RoccatMacroEditorBasicTreeView *tree_view) {
	RoccatMacroEditorBasicTreeViewPrivate *priv = ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW_GET_PRIVATE(tree_view);
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;

	tree_view->priv = priv;

	priv->menu = GTK_MENU(menu_new(tree_view));
	g_object_ref_sink(priv->menu);

	column = gtk_tree_view_column_new();

	renderer = gtk_cell_renderer_pixbuf_new();
	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE);
	gtk_tree_view_column_add_attribute(GTK_TREE_VIEW_COLUMN(column), renderer, "icon-name", roccat_macro_editor_basic_list_store_icon_column());

	renderer = gtk_cell_renderer_spin_new();
	g_object_set(renderer,
			"editable", TRUE,
			"adjustment", gtk_adjustment_new(1, 1, ROCCAT_MACRO_KEYSTROKE_PERIOD_MAX, 1, 1000, 0),
			NULL);
	g_signal_connect(renderer, "edited", G_CALLBACK(delay_edited_cb), tree_view);
	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE);
	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer,
			"text", roccat_macro_editor_basic_list_store_text_column(),
			"visible", roccat_macro_editor_basic_list_store_is_not_key_column(),
			NULL);

	renderer = gtk_cell_renderer_text_new();
	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE);
	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer,
			"text", roccat_macro_editor_basic_list_store_text_column(),
			"visible", roccat_macro_editor_basic_list_store_is_key_column(),
			NULL);

	gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);

	g_signal_connect(G_OBJECT(tree_view), "button-press-event", G_CALLBACK(popup_menu_on_right_mouse_button_cb), NULL);
}

static void roccat_macro_editor_basic_tree_view_finalize(GObject *object) {
	RoccatMacroEditorBasicTreeViewPrivate *priv = ROCCAT_MACRO_EDITOR_BASIC_TREE_VIEW(object)->priv;
	g_object_unref(priv->menu);
	G_OBJECT_CLASS(roccat_macro_editor_basic_tree_view_parent_class)->finalize(object);
}

static void roccat_macro_editor_basic_tree_view_class_init(RoccatMacroEditorBasicTreeViewClass *klass) {
	GObjectClass *gobject_class;

	gobject_class = G_OBJECT_CLASS(klass);

	gobject_class->finalize = roccat_macro_editor_basic_tree_view_finalize;

	g_type_class_add_private(klass, sizeof(RoccatMacroEditorBasicTreeViewPrivate));
}
