/*
 * 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 "valo_orig_macro.h"
#include "g_roccat_helper.h"
#include "roccat_helper.h"

static guint8 valo_original_macro_calc_checksum(ValoOriginalMacro const *macro) {
	return ROCCAT_BYTESUM_PARTIALLY(macro, ValoOriginalMacro, macro_name[0], checksum);
}

static void valo_original_macro_set_checksum(ValoOriginalMacro *macro) {
	macro->checksum = valo_original_macro_calc_checksum(macro);
}

static void valo_original_macro_set_macro_name(ValoOriginalMacro *macro, gchar const *new_name) {
	g_strlcpy((gchar *)(macro->macro_name), new_name, VALO_ORIGINAL_MACRO_NAME_LENGTH);
}

static void roccat_macro_keystroke_to_valo_original_macro_keystroke(RoccatMacroKeystroke const *from, ValoOriginalMacroKeystroke *to) {
	to->key = from->key;
	valo_original_macro_keystroke_set_period(to, roccat_macro_keystroke_get_period(from));
	if (from->action == ROCCAT_MACRO_KEYSTROKE_ACTION_PRESS)
		to->action = VALO_ORIGINAL_MACRO_KEYSTROKE_ACTION_PRESS;
	else
		to->action = VALO_ORIGINAL_MACRO_KEYSTROKE_ACTION_RELEASE;
}

static ValoOriginalMacro *roccat_macro_to_valo_original_macro(RoccatMacro const *roccat_macro) {
	ValoOriginalMacro *result;
	guint i, count;

	result = g_malloc0(sizeof(ValoOriginalMacro));
	valo_original_macro_set_macro_name(result, roccat_macro->macro);

	count = roccat_macro_keystrokes_get_count(&roccat_macro->keystrokes);
	g_assert(count <= VALO_ORIGINAL_MACRO_KEYSTROKES_NUM);
	valo_original_macro_set_count(result, count);

	for (i = 0; i < count; ++i) {
		roccat_macro_keystroke_to_valo_original_macro_keystroke(&roccat_macro->keystrokes.keystrokes[i], &result->keystrokes[i]);
	}

	valo_original_macro_set_checksum(result);

	return result;
}

gboolean valo_original_macros_export(gchar const *filename, RoccatMacros *roccat_macros, GError **error) {
	GKeyFile *valo_original_macro_file = g_key_file_new();
	RoccatMacro *roccat_macro;
	ValoOriginalMacro *valo_original_macro;
	gchar *data, **groups, **group, **keys, **key;
	gsize length;
	guint macroset_counter = 0;
	guint macro_counter = 0;
	gchar *intkey;

	groups = roccat_macros_get_macro_sets(roccat_macros, NULL);
	for (group = groups; *group; ++group) {
		keys = roccat_macros_get_macros(roccat_macros, *group, NULL, error);
		if (*error)
			goto free_groups;

		intkey = g_strdup_printf("%i", macroset_counter);
		g_key_file_set_string(valo_original_macro_file, VALO_ORIGINAL_MACRO_MAIN_GROUP_NAME, intkey, *group);
		g_free(intkey);

		for (key = keys; *key; ++key) {
			roccat_macro = roccat_macros_get(roccat_macros, *group, *key, error);
			if (!roccat_macro)
				goto free_keys;

			valo_original_macro = roccat_macro_to_valo_original_macro(roccat_macro);
			roccat_macro_free(roccat_macro);
			if (!valo_original_macro)
				break;

			intkey = g_strdup_printf("%i", macro_counter);
			roccat_key_file_set_binary(valo_original_macro_file, *group, intkey, valo_original_macro, sizeof(ValoOriginalMacro));
			g_free(intkey);
			g_free(valo_original_macro);
			++macro_counter;
		}
		g_key_file_set_integer(valo_original_macro_file, *group, VALO_ORIGINAL_MACRO_COUNT_NAME, macro_counter);
		g_strfreev(keys);
		++macroset_counter;
		macro_counter = 0;
	}
	g_strfreev(groups);
	g_key_file_set_integer(valo_original_macro_file, VALO_ORIGINAL_MACRO_MAIN_GROUP_NAME, VALO_ORIGINAL_MACRO_COUNT_NAME, macroset_counter);

	data = g_key_file_to_data(valo_original_macro_file, &length, error);
	g_key_file_free(valo_original_macro_file);
	if (*error)
		goto exit;

	g_file_set_contents(filename, data, length, error);
	g_free(data);
	if (*error)
		goto exit;

	return TRUE;
free_keys:
	g_strfreev(keys);
free_groups:
	g_strfreev(groups);
	g_key_file_free(valo_original_macro_file);
exit:
	return FALSE;
}
