/* ncmpc (Ncurses MPD Client)
 * Copyright 2004-2021 The Music Player Daemon Project
 *
 * This program 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.
 *
 * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "Bindings.hxx"
#include "Command.hxx"
#include "KeyName.hxx"
#include "i18n.h"

#include <assert.h>
#include <stdio.h>

const char *
KeyBindings::GetFirstKeyName(Command command) const noexcept
{
	const auto &b = key_bindings[size_t(command)];
	return b.keys.front() != 0
		? GetLocalizedKeyName(b.keys[0])
		: nullptr;
}

std::string
KeyBindings::GetKeyNames(Command command) const noexcept
{
	const auto &b = key_bindings[size_t(command)];

	std::string s = GetLocalizedKeyName(b.keys[0]);

	for (size_t i = 1; i < b.keys.size() && b.keys[i] != 0; ++i) {
		s.push_back(' ');
		s.append(GetLocalizedKeyName(b.keys[i]));
	}
	return s;
}

Command
KeyBindings::FindKey(int key) const noexcept
{
	assert(key != 0);

	for (size_t i = 0; i < size_t(Command::NONE); ++i) {
		if (key_bindings[i].HasKey(key))
			return Command(i);
	}

	return Command::NONE;
}

#ifndef NCMPC_MINI

bool
KeyBindings::Check(char *buf, size_t bufsize) const noexcept
{
	bool success = true;

	for (size_t i = 0; i < size_t(Command::NONE); ++i) {
		for (const auto key : key_bindings[i].keys) {
			if (key == 0)
				break;

			Command cmd;
			if ((cmd = FindKey(key)) != Command(i)) {
				if (buf) {
					snprintf(buf, bufsize,
						 _("Key %s assigned to %s and %s"),
						 GetLocalizedKeyName(key),
						 get_key_command_name(Command(i)),
						 get_key_command_name(cmd));
				} else {
					fprintf(stderr,
						_("Key %s assigned to %s and %s"),
						GetLocalizedKeyName(key),
						get_key_command_name(Command(i)),
						get_key_command_name(cmd));
					fputc('\n', stderr);
				}
				success = false;
			}
		}
	}

	return success;
}

void
KeyBinding::WriteToFile(FILE *f, const command_definition_t &cmd,
			bool comment) const noexcept
{
	fprintf(f, "## %s\n", cmd.description);
	if (comment)
		fprintf(f, "#");
	fprintf(f, "key %s = ", cmd.name);

	if (keys.front() == 0) {
		fputs("0\n\n", f);
		return;
	}

	bool first = true;
	for (const auto key : keys) {
		if (key == 0)
			break;

		if (first)
			first = false;
		else
			fprintf(f, ",  ");

		fputs(GetKeyName(key), f);
	}
	fprintf(f,"\n\n");
}

bool
KeyBindings::WriteToFile(FILE *f, int flags) const noexcept
{
	const auto *cmds = get_command_definitions();

	if (flags & KEYDEF_WRITE_HEADER)
		fprintf(f, "## Key bindings for ncmpc (generated by ncmpc)\n\n");

	for (size_t i = 0; i < size_t(Command::NONE) && !ferror(f); ++i) {
		if (key_bindings[i].modified || flags & KEYDEF_WRITE_ALL) {
			key_bindings[i].WriteToFile(f, cmds[i],
						    flags & KEYDEF_COMMENT_ALL);
		}
	}

	return ferror(f) == 0;
}

#endif /* NCMPC_MINI */
