/* SPDX-FileCopyrightText: 2025 - Sébastien Wilmet
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#include "gedit-spell-document.h"

#define METADATA_KEY_SPELL_LANGUAGE   "gedit-spell-language"

#define METADATA_KEY_SPELL_ENABLED    "gedit-spell-enabled"
#define METADATA_VALUE_SPELL_ENABLED  "true"
#define METADATA_VALUE_SPELL_DISABLED "false"

GspellChecker *
gedit_spell_document_get_spell_checker (GeditDocument *document)
{
	GspellTextBuffer *gspell_buffer;

	g_return_val_if_fail (GEDIT_IS_DOCUMENT (document), NULL);

	gspell_buffer = gspell_text_buffer_get_from_gtk_text_buffer (GTK_TEXT_BUFFER (document));
	return gspell_text_buffer_get_spell_checker (gspell_buffer);
}

void
gedit_spell_document_set_metadata_for_language (GeditDocument        *document,
						const GspellLanguage *language)
{
	const gchar *language_code = NULL;

	g_return_if_fail (GEDIT_IS_DOCUMENT (document));

	if (language != NULL)
	{
		language_code = gspell_language_get_code (language);
	}

	gedit_document_set_metadata (document,
				     METADATA_KEY_SPELL_LANGUAGE, language_code,
				     NULL);
}

static const GspellLanguage *
get_metadata_for_language (GeditDocument *document)
{
	gchar *language_code;
	const GspellLanguage *language = NULL;

	g_return_val_if_fail (GEDIT_IS_DOCUMENT (document), NULL);

	language_code = gedit_document_get_metadata (document, METADATA_KEY_SPELL_LANGUAGE);

	if (language_code != NULL)
	{
		language = gspell_language_lookup (language_code);
		g_free (language_code);
	}

	return language;
}

static const GspellLanguage *
get_initial_language_setting (GeditDocument *document)
{
	const GspellLanguage *language;

	language = get_metadata_for_language (document);

	if (language == NULL)
	{
		GSettings *settings;
		gchar *language_code;

		settings = g_settings_new ("org.gnome.gedit.plugins.spell");
		language_code = g_settings_get_string (settings, "spell-checking-language");
		g_object_unref (settings);

		language = gspell_language_lookup (language_code);
		g_free (language_code);
	}

	return language;
}

void
gedit_spell_document_set_metadata_for_inline_spell_checking (GeditDocument *document,
							     gboolean       inline_spell_checking)
{
	const gchar *metadata_value;

	g_return_if_fail (GEDIT_IS_DOCUMENT (document));

	if (inline_spell_checking)
	{
		metadata_value = METADATA_VALUE_SPELL_ENABLED;
	}
	else
	{
		metadata_value = METADATA_VALUE_SPELL_DISABLED;
	}

	gedit_document_set_metadata (document,
				     METADATA_KEY_SPELL_ENABLED, metadata_value,
				     NULL);
}

void
gedit_spell_document_get_metadata_for_inline_spell_checking (GeditDocument *document,
							     gboolean      *metadata_exists,
							     gboolean      *metadata_value)
{
	gchar *metadata_value_str;

	g_return_if_fail (GEDIT_IS_DOCUMENT (document));
	g_return_if_fail (metadata_exists != NULL);
	g_return_if_fail (metadata_value != NULL);

	metadata_value_str = gedit_document_get_metadata (document, METADATA_KEY_SPELL_ENABLED);

	if (metadata_value_str == NULL)
	{
		*metadata_exists = FALSE;
	}
	else
	{
		*metadata_exists = TRUE;
		*metadata_value = g_str_equal (metadata_value_str, METADATA_VALUE_SPELL_ENABLED);

		g_free (metadata_value_str);
	}
}

static void
language_notify_cb (GspellChecker *checker,
		    GParamSpec    *pspec,
		    GeditDocument *document)
{
	const GspellLanguage *language;

	language = gspell_checker_get_language (checker);
	gedit_spell_document_set_metadata_for_language (document, language);
}

void
gedit_spell_document_setup_spell_checker (GeditDocument *document)
{
	GspellChecker *checker;
	const GspellLanguage *language;
	GspellTextBuffer *gspell_buffer;

	g_return_if_fail (GEDIT_IS_DOCUMENT (document));

	checker = gedit_spell_document_get_spell_checker (document);
	if (checker != NULL)
	{
		/* Already done. */
		return;
	}

	language = get_initial_language_setting (document);
	checker = gspell_checker_new (language);

	g_signal_connect_object (checker,
				 "notify::language",
				 G_CALLBACK (language_notify_cb),
				 document,
				 G_CONNECT_DEFAULT);

	gspell_buffer = gspell_text_buffer_get_from_gtk_text_buffer (GTK_TEXT_BUFFER (document));
	gspell_text_buffer_set_spell_checker (gspell_buffer, checker);
	g_object_unref (checker);
}

void
gedit_spell_document_restore_language (GeditDocument *document)
{
	GspellChecker *checker;
	const GspellLanguage *language;

	g_return_if_fail (GEDIT_IS_DOCUMENT (document));

	checker = gedit_spell_document_get_spell_checker (document);
	if (checker == NULL)
	{
		return;
	}

	language = get_initial_language_setting (document);
	if (language == NULL)
	{
		return;
	}

	g_signal_handlers_block_by_func (checker, language_notify_cb, document);
	gspell_checker_set_language (checker, language);
	g_signal_handlers_unblock_by_func (checker, language_notify_cb, document);
}
