/*
 * 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 "luaconfig_application.h"
#include "roccat_config_window.h"
#include "luaconfig_profile_page.h"
#include "luaconfig_surface_check.h"
#include "luaconfig_configuration_dialog.h"
#include "roccat_warning_dialog.h"
#include "roccat_save_dialog.h"

struct _LuaconfigApplication {
	RoccatDevice *lua;
	LuaDeviceScanner *device_scanner;
	RoccatConfigWindow *window;
	LuaconfigProfilePage *profile_page;
	RoccatKeyFile *config;
};

static gboolean warn_if_no_device(LuaconfigApplication *app) {
	return roccat_no_device_warning_dialog(GTK_WINDOW(app->window), app->lua, LUA_DEVICE_NAME);
}

static gboolean add_cb(RoccatDevice *device, gpointer user_data) {
	LuaconfigApplication *app = (LuaconfigApplication *)user_data;

	if (app->lua) {
		roccat_multiple_device_warning_dialog(GTK_WINDOW(app->window), LUA_DEVICE_NAME);
		return TRUE;
	}

	app->lua = device;

	roccat_config_window_set_title_connected(app->window, LUA_DEVICE_NAME);

	return FALSE;
}

static gboolean remove_cb(RoccatDevice *device, gpointer user_data) {
	LuaconfigApplication *app = (LuaconfigApplication *)user_data;

	roccat_device_free(app->lua);
	app->lua = NULL;

	roccat_config_window_set_title_disconnected(app->window);

	return TRUE;
}

static gboolean save_unsaved(LuaconfigApplication *app, LuaRmp *rmp, GError **error) {
	if (app->lua)
		lua_rmp_save(app->lua, rmp, error);
	else
		lua_rmp_save_actual(rmp, error);

	if (*error)
		return FALSE;
	else {
		/* If data has been saved, set this as new actual state in profile_page */
		luaconfig_profile_page_set_rmp(app->profile_page, rmp);
		return TRUE;
	}
}

static gboolean display_quit_dialog(LuaconfigApplication *app) {
	LuaRmp *rmp;
	gboolean retval;
	GError *error = NULL;

	rmp = luaconfig_profile_page_get_rmp(app->profile_page);

	if (!lua_rmp_get_modified(rmp)) {
		lua_rmp_free(rmp);
		return TRUE;
	}

	switch (roccat_save_unsaved_dialog(GTK_WINDOW(app->window), TRUE)) {
	case GTK_RESPONSE_CANCEL:
		retval = FALSE;
		break;
	case GTK_RESPONSE_ACCEPT:
		warn_if_no_device(app);
		retval = save_unsaved(app, rmp, &error);
		roccat_handle_error_dialog(GTK_WINDOW(app->window), "Error storing unsaved data", &error);
		break;
	default:
		retval = TRUE;
		break;
	}
	lua_rmp_free(rmp);
	return retval;
}

static gboolean delete_event_cb(GtkWidget *window, GdkEvent *event, gpointer user_data) {
	LuaconfigApplication *app = (LuaconfigApplication *)user_data;

	return !display_quit_dialog(app);
}

static void destroy_event_cb(GtkWidget *window, gpointer user_data) {
	LuaconfigApplication *app = (LuaconfigApplication *)user_data;
	gtk_main_quit();
	app->window = NULL;
}

static void save_profile_to_device_cb(LuaconfigProfilePage *profile_page, gpointer user_data) {
	LuaconfigApplication *app = (LuaconfigApplication *)user_data;
	LuaRmp *rmp = luaconfig_profile_page_get_rmp(profile_page);
	GError *error = NULL;

	warn_if_no_device(app);
	save_unsaved(app, rmp, &error);
	roccat_handle_error_dialog(GTK_WINDOW(app->window), "Error storing unsaved data", &error);

	lua_rmp_free(rmp);
}

static void add_file_filter_to_file_chooser(GtkFileChooser *chooser) {
	GtkFileFilter *filter;
	filter = gtk_file_filter_new();
	gtk_file_filter_set_name(filter, "Lua Windows profiles");
	gtk_file_filter_add_pattern(filter, "*.rmp");
	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter);

	filter = gtk_file_filter_new();
	gtk_file_filter_set_name(filter, "All files");
	gtk_file_filter_add_pattern(filter, "*");
	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter);
}

static void save_profile_to_file_cb(LuaconfigProfilePage *profile_page, gpointer user_data) {
	LuaconfigApplication *app = (LuaconfigApplication *)user_data;
	GtkWidget *dialog;
	gchar *filename, *path;
	GError *error = NULL;
	LuaRmp *rmp;

	dialog = gtk_file_chooser_dialog_new("Save profile",
			GTK_WINDOW(app->window),
			GTK_FILE_CHOOSER_ACTION_SAVE,
			GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
			GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
			NULL);

	add_file_filter_to_file_chooser(GTK_FILE_CHOOSER(dialog));
	path = lua_configuration_get_rmp_path(app->config);
	gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
	g_free(path);

	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
		path = g_path_get_dirname(filename);
		lua_configuration_set_rmp_path(app->config, path);
		g_free(path);

		rmp = luaconfig_profile_page_get_rmp(app->profile_page);
		lua_rmp_write_with_path(filename, rmp, &error);
		lua_rmp_free(rmp);
		if (error) {
			roccat_warning_dialog(GTK_WINDOW(dialog), "Error saving rmp", error->message);
			g_error_free(error);
		}

		g_free(filename);
	}
	gtk_widget_destroy(dialog);
}

static void load_profile_from_file_cb(LuaconfigProfilePage *profile_page, gpointer user_data) {
	LuaconfigApplication *app = (LuaconfigApplication *)user_data;
	GtkWidget *dialog;
	gchar *filename, *path;
	GError *error = NULL;
	LuaRmp *rmp;

	dialog = gtk_file_chooser_dialog_new("Load profile",
			GTK_WINDOW(app->window),
			GTK_FILE_CHOOSER_ACTION_OPEN,
			GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
			GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
			NULL);

	add_file_filter_to_file_chooser(GTK_FILE_CHOOSER(dialog));
	path = lua_configuration_get_rmp_path(app->config);
	gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
	g_free(path);

	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
		path = g_path_get_dirname(filename);
		lua_configuration_set_rmp_path(app->config, path);
		g_free(path);

		rmp = lua_rmp_read_with_path(filename, &error);
		if (error) {
			roccat_warning_dialog(GTK_WINDOW(dialog), "Error loading rmp", error->message);
			g_error_free(error);
		} else {
			/* Make sure it has to be saved */
			lua_rmp_set_modified(rmp);
			luaconfig_profile_page_set_rmp(app->profile_page, rmp);
			lua_rmp_free(rmp);
		}

		g_free(filename);
	}

	gtk_widget_destroy(dialog);
}

static void save_all_cb(GtkMenuItem *item, gpointer user_data) {
	LuaconfigApplication *app = (LuaconfigApplication *)user_data;
	LuaRmp *rmp = luaconfig_profile_page_get_rmp(app->profile_page);
	GError *error = NULL;

	warn_if_no_device(app);
	save_unsaved(app, rmp, &error);
	roccat_handle_error_dialog(GTK_WINDOW(app->window), "Error storing unsaved data", &error);

	lua_rmp_free(rmp);
}

static void menu_misc_surface_check_cb(GtkMenuItem *item, gpointer user_data) {
	LuaconfigApplication *app = (LuaconfigApplication *)user_data;
	luaconfig_surface_check(GTK_WINDOW(app->window), app->lua);
}

static GtkWidget *menu_misc_new(LuaconfigApplication *app) {
	GtkWidget *menu_item;
	GtkWidget *submenu_item;
	GtkWidget *sub_menu;

	menu_item = gtk_menu_item_new_with_label("Misc");
	sub_menu = gtk_menu_new();
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), sub_menu);

	submenu_item = gtk_image_menu_item_new_with_label("Surface check");
	gtk_menu_shell_append(GTK_MENU_SHELL(sub_menu), submenu_item);
	g_signal_connect(G_OBJECT(submenu_item), "activate", G_CALLBACK(menu_misc_surface_check_cb), app);

	gtk_widget_show_all(menu_item);

	return menu_item;
}

LuaconfigApplication *luaconfig_application_new(void) {
	LuaconfigApplication *app;
	LuaRmp *rmp;

	app = (LuaconfigApplication *)g_malloc0(sizeof(LuaconfigApplication));

	app->config = lua_configuration_load();

	app->window = ROCCAT_CONFIG_WINDOW(roccat_config_window_new(LUA_DEVICE_NAME));
	gtk_widget_show(GTK_WIDGET(app->window));

	app->profile_page = LUACONFIG_PROFILE_PAGE(luaconfig_profile_page_new());
	roccat_config_window_append_page(app->window, GTK_WIDGET(app->profile_page), gtk_label_new(NULL));

	roccat_config_window_menu_insert(app->window, GTK_MENU_ITEM(menu_misc_new(app)));

	rmp = lua_rmp_load_actual();
	luaconfig_profile_page_set_rmp(app->profile_page, rmp);
	lua_rmp_free(rmp);

	g_signal_connect(G_OBJECT(app->window), "destroy", G_CALLBACK(destroy_event_cb), app);
	g_signal_connect(G_OBJECT(app->window), "delete-event", G_CALLBACK(delete_event_cb), app);
	g_signal_connect(G_OBJECT(app->window), "save-all", G_CALLBACK(save_all_cb), app);
	g_signal_connect(G_OBJECT(app->profile_page), "load-from-file", G_CALLBACK(load_profile_from_file_cb), app);
	g_signal_connect(G_OBJECT(app->profile_page), "save-to-file", G_CALLBACK(save_profile_to_file_cb), app);
	g_signal_connect(G_OBJECT(app->profile_page), "save-to-device", G_CALLBACK(save_profile_to_device_cb), app);

	app->device_scanner = lua_device_scanner_new(add_cb, remove_cb, app);

	/* if a device is already plugged in, add_cb has already been executed */
	warn_if_no_device(app);

	return app;
}

void luaconfig_application_free(LuaconfigApplication *app) {
	lua_device_scanner_free(app->device_scanner);
	app->device_scanner = NULL;

	roccat_device_free(app->lua);
	app->lua = NULL;

	if (app->window) {
		gtk_widget_destroy(GTK_WIDGET(app->window));
		app->window = NULL;
	}

	luaconfig_configuration_save(GTK_WINDOW(app->window), app->config);
	lua_configuration_free(app->config);
	app->config = NULL;

	g_free(app);
}
