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

typedef struct _RoccatMacroKeystrokesV1 RoccatMacroKeystrokesV1;

struct _RoccatMacroKeystrokesV1 {
	guint16 count;
	RoccatMacroKeystroke keystrokes[ROCCAT_MACRO_KEYSTROKES_NUM];
};

static RoccatMacroKeystrokes *roccat_macro_keystrokes_v1_to_roccat_macro_keystrokes(RoccatMacroKeystrokesV1 const *v1) {
	RoccatMacroKeystrokes *result;
	guint i;

	result = roccat_macro_keystrokes_new();
	result->count = v1->count;

	for (i = 0; i < ROCCAT_MACRO_KEYSTROKES_NUM; ++i) {
		result->keystrokes[i].key = v1->keystrokes[i].key;
		result->keystrokes[i].action = v1->keystrokes[i].action;
		result->keystrokes[i].period = v1->keystrokes[i].period;
	}
	result->loop = 1;

	return result;
}

RoccatMacroKeystrokes *roccat_key_file_get_roccat_macro_keystrokes(GKeyFile *key_file,
		gchar const *macro_set_name, gchar const *macro_name,
		GError **error) {
	RoccatMacroKeystrokesV1 *roccat_macro_keystrokes_v1;
	RoccatMacroKeystrokes *roccat_macro_keystrokes;

	roccat_macro_keystrokes = roccat_key_file_get_binary(key_file, macro_set_name, macro_name, sizeof(RoccatMacroKeystrokes), error);
	if (roccat_macro_keystrokes)
		return roccat_macro_keystrokes;

	if (!g_error_matches(*error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE))
		return NULL;
	g_clear_error(error);

	roccat_macro_keystrokes_v1 = roccat_key_file_get_binary(key_file, macro_set_name, macro_name, sizeof(RoccatMacroKeystrokesV1), error);
	if (roccat_macro_keystrokes_v1) {
		roccat_macro_keystrokes = roccat_macro_keystrokes_v1_to_roccat_macro_keystrokes(roccat_macro_keystrokes_v1);
		g_free(roccat_macro_keystrokes_v1);
		return roccat_macro_keystrokes;
	}

	return NULL;
}

gboolean roccat_macro_keystrokes_add(RoccatMacroKeystrokes *keystrokes, RoccatMacroKeystroke const *keystroke) {
	guint count = roccat_macro_keystrokes_get_count(keystrokes);
	/* index = count - 1; new_index = index + 1 */
	guint new_index = count;

	g_assert(keystrokes->count <= ROCCAT_MACRO_KEYSTROKES_NUM);
	g_assert(keystroke->action == ROCCAT_MACRO_KEYSTROKE_ACTION_PRESS || keystroke->action == ROCCAT_MACRO_KEYSTROKE_ACTION_RELEASE);

	if (new_index >= ROCCAT_MACRO_KEYSTROKES_NUM)
		return FALSE;

	roccat_macro_keystrokes_set_count(keystrokes, count + 1);
	keystrokes->keystrokes[new_index].action = keystroke->action;
	keystrokes->keystrokes[new_index].key = keystroke->key;
	/* no change in endianess and size */
	keystrokes->keystrokes[new_index].period = keystroke->period;

	return TRUE;
}

void roccat_macro_keystrokes_clear(RoccatMacroKeystrokes *keystrokes) {
	memset(keystrokes, 0, sizeof(RoccatMacroKeystrokes));
	keystrokes->loop = 1;
}

void roccat_macro_keystrokes_init(RoccatMacroKeystrokes *keystrokes) {
	roccat_macro_keystrokes_clear(keystrokes);
}

RoccatMacroKeystrokes *roccat_macro_keystrokes_new(void) {
	RoccatMacroKeystrokes *keystrokes;
	keystrokes = g_malloc(sizeof(RoccatMacroKeystrokes));
	roccat_macro_keystrokes_init(keystrokes);
	return keystrokes;
}

void roccat_macro_keystrokes_free(RoccatMacroKeystrokes *keystrokes) {
	g_free(keystrokes);
}

void roccat_macro_keystrokes_copy(RoccatMacroKeystrokes const *from, RoccatMacroKeystrokes *to) {
	memcpy(to, from, sizeof(RoccatMacroKeystrokes));
}

RoccatMacroKeystrokes *roccat_macro_keystrokes_dup(RoccatMacroKeystrokes const *old) {
	return g_memdup(old, sizeof(RoccatMacroKeystrokes));
}

gboolean roccat_macro_keystrokes_have_mouse_keystroke(RoccatMacroKeystrokes const *keystrokes) {
	guint count = roccat_macro_keystrokes_get_count(keystrokes);
	guint i;

	for (i = 0; i < count; ++i) {
		if (keystrokes->keystrokes[i].key >= ROCCAT_MACRO_KEYSTROKE_KEY_BUTTON_LEFT &&
				keystrokes->keystrokes[i].key <= ROCCAT_MACRO_KEYSTROKE_KEY_BUTTON_MIDDLE)
			return TRUE;
	}

	return FALSE;
}
