/*
 * 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/roccat.h"
#include "kone_orig_macro.h"
#include "g_roccat_helper.h"
#include <string.h>

static void roccat_macro_import_iterate_keys(RoccatMacros *roccat_macros,
		GKeyFile *other_macro_file,
		gchar const *group_name,
		gboolean (*eval_key)(RoccatMacros *, GKeyFile *, gchar const *, gchar const *, GError **)) {
	gchar **key_names, **key_name;
	GError *error = NULL;

	key_names = g_key_file_get_keys(other_macro_file, group_name, NULL, &error);
	if (!key_names)
		g_error("iterate_keys(): %s", error->message);

	key_name = key_names;
	while (*key_name) {
		if (!eval_key(roccat_macros, other_macro_file, group_name, *key_name, &error)) {
			g_critical("%s", error->message);
			g_clear_error(&error);
		}
		++key_name;
	}
	g_strfreev(key_names);
}

static void roccat_macro_import_iterate_groups(RoccatMacros *roccat_macros,
		GKeyFile *other_macro_file,
		void (*eval_group)(RoccatMacros *, GKeyFile *, gchar const *)) {
	gchar **groups, **group;
	groups = g_key_file_get_groups(other_macro_file, NULL);
	group = groups;
	while (*group) {
		eval_group(roccat_macros, other_macro_file, *group);
		++group;
	}
	g_strfreev(groups);
}

static RoccatMacroKeystrokes *kone_original_macro_to_roccat_macro_keystrokes(KoneOriginalMacro const *kone_original_macro) {
	RoccatMacroKeystrokes *result = g_malloc0(sizeof(RoccatMacroKeystrokes));
	guint32 count;
	guint i;

	count = kone_original_macro_get_count(kone_original_macro);
	g_assert(count <= ROCCAT_MACRO_KEYSTROKES_NUM);
	roccat_macro_keystrokes_set_count(result, count);

	for (i = 0; i < count; ++i) {
		result->keystrokes[i].key = kone_original_macro->keystrokes[i].key;
		switch (kone_original_macro->keystrokes[i].action) {
		case KONE_ORIGINAL_MACRO_KEYSTROKE_ACTION_PRESS:
			result->keystrokes[i].action = ROCCAT_MACRO_KEYSTROKE_ACTION_PRESS;
			break;
		case KONE_ORIGINAL_MACRO_KEYSTROKE_ACTION_RELEASE:
			result->keystrokes[i].action = ROCCAT_MACRO_KEYSTROKE_ACTION_RELEASE;
			break;
		}
		roccat_macro_keystroke_set_period(&result->keystrokes[i], kone_original_macro_keystroke_get_period(&kone_original_macro->keystrokes[i]));
	}

	return result;
}

static gboolean eval_kone_key(RoccatMacros *roccat_macros, GKeyFile *kone_original_macro_file, gchar const *group_name, gchar const *key_name, GError **error) {
	KoneOriginalMacro *kone_original_macro;
	RoccatMacroKeystrokes *roccat_macro_keystrokes;
	RoccatMacro *roccat_macro;

	if (strcmp(key_name, KONE_ORIGINAL_MACRO_COUNT_NAME)) {
		kone_original_macro = roccat_key_file_get_binary(kone_original_macro_file, group_name, key_name, sizeof(KoneOriginalMacro), error);
		if (!kone_original_macro)
			return FALSE;

		roccat_macro_keystrokes = kone_original_macro_to_roccat_macro_keystrokes(kone_original_macro);
		roccat_macro = roccat_macro_new(group_name, (gchar const *)kone_original_macro->macro_name, roccat_macro_keystrokes);
		roccat_macros_set(roccat_macros, roccat_macro);

		g_free(roccat_macro);
		g_free(roccat_macro_keystrokes);
		g_free(kone_original_macro);
	}
	return TRUE;
}

static void eval_kone_group(RoccatMacros *roccat_macros, GKeyFile *kone_original_macro_file, gchar const *group_name) {
	if (strcmp(group_name, KONE_ORIGINAL_MACRO_MAIN_GROUP_NAME))
		roccat_macro_import_iterate_keys(roccat_macros, kone_original_macro_file, group_name, eval_kone_key);
}

static gboolean is_kone_file(GKeyFile *key_file) {
	if (g_key_file_has_group(key_file, KONE_ORIGINAL_MACRO_MAIN_GROUP_NAME))
		return TRUE;
	return FALSE;
}

RoccatMacros *kone_original_macros_import(gchar const *filename, GError **error) {
	RoccatMacros *roccat_macros;
	GKeyFile *kone_original_macro_file;

	kone_original_macro_file = g_key_file_new();
	roccat_macros = roccat_macros_new();

	if (!g_key_file_load_from_file(kone_original_macro_file, filename, G_KEY_FILE_NONE, error))
		goto free;

	if (!is_kone_file(kone_original_macro_file)) {
		g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_INVAL, "%s is no Kone macro file", filename);
		goto free;
	}

	roccat_macro_import_iterate_groups(roccat_macros, kone_original_macro_file, eval_kone_group);

	g_key_file_free(kone_original_macro_file);

	return roccat_macros;
free:
	g_key_file_free(kone_original_macro_file);
	roccat_macros_free(roccat_macros);
	return NULL;
}
