/*
 * Pidgin - Internet Messenger
 * Copyright (C) Pidgin Developers <devel@pidgin.im>
 *
 * Pidgin is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * 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, see <https://www.gnu.org/licenses/>.
 */

#include <birb.h>

#include <purple.h>

#include <adwaita.h>

#include "pidgincredentialprefs.h"

#include "pidgincredentialproviderrow.h"

struct _PidginCredentialPrefs {
	AdwPreferencesPage parent;

	GtkWidget *credential_list;
};

G_DEFINE_FINAL_TYPE(PidginCredentialPrefs, pidgin_credential_prefs,
                    ADW_TYPE_PREFERENCES_PAGE)

/******************************************************************************
 * Helpers
 *****************************************************************************/
static GtkWidget *
pidgin_credential_prefs_create_row(GObject *item,
                                   G_GNUC_UNUSED gpointer data)
{
	return pidgin_credential_provider_row_new(PURPLE_CREDENTIAL_PROVIDER(item));
}

static int
pidgin_credential_prefs_sort_rows(gconstpointer a, gconstpointer b,
                                  G_GNUC_UNUSED gpointer user_data)
{
	PurpleCredentialProvider *provider_a = (gpointer)a;
	PurpleCredentialProvider *provider_b = (gpointer)b;
	const char *id1 = NULL;
	gboolean is_noop1 = FALSE;
	const char *id2 = NULL;
	gboolean is_noop2 = FALSE;

	id1 = purple_credential_provider_get_id(provider_a);
	is_noop1 = birb_str_equal(id1, "noop-provider");

	id2 = purple_credential_provider_get_id(provider_b);
	is_noop2 = birb_str_equal(id2, "noop-provider");

	/* Sort None provider after everything else. */
	if (is_noop1 && is_noop2) {
		return 0;
	} else if (is_noop1 && !is_noop2) {
		return 1;
	} else if (!is_noop1 && is_noop2) {
		return -1;
	}

	/* Sort normally by ID. */
	return g_strcmp0(id1, id2);
}

static void
pidgin_credential_prefs_list_row_activated_cb(G_GNUC_UNUSED GtkListBox *box,
                                              GtkListBoxRow *row,
                                              G_GNUC_UNUSED gpointer data)
{
	PurpleCredentialManager *manager = NULL;
	PurpleCredentialProvider *provider = NULL;
	const char *id = NULL;
	GError *error = NULL;

	provider = pidgin_credential_provider_row_get_provider(
	    PIDGIN_CREDENTIAL_PROVIDER_ROW(row));
	id = purple_credential_provider_get_id(provider);

	manager = purple_credential_manager_get_default();
	if(purple_credential_manager_set_active(manager, id, &error)) {
		return;
	}

	purple_debug_warning("credential-prefs", "failed to set the active "
			     "credential provider to '%s': %s",
			     id, error ? error->message : "unknown error");

	g_clear_error(&error);
}

static void
pidgin_credential_prefs_set_active_provider(PidginCredentialPrefs *prefs,
                                            PurpleCredentialProvider *active)
{
	GtkWidget *child = NULL;

	for (child = gtk_widget_get_first_child(prefs->credential_list);
	     child;
	     child = gtk_widget_get_next_sibling(child))
	{
		PidginCredentialProviderRow *row = NULL;
		PurpleCredentialProvider *provider = NULL;

		row = PIDGIN_CREDENTIAL_PROVIDER_ROW(child);
		provider = pidgin_credential_provider_row_get_provider(row);

		pidgin_credential_provider_row_set_active(row, provider == active);
	}
}

static void
pidgin_credential_prefs_active_provider_changed_cb(G_GNUC_UNUSED PurpleCredentialManager *manager,
                                                   G_GNUC_UNUSED PurpleCredentialProvider *previous,
                                                   PurpleCredentialProvider *current,
                                                   gpointer data)
{
	PidginCredentialPrefs *prefs = PIDGIN_CREDENTIAL_PREFS(data);

	pidgin_credential_prefs_set_active_provider(prefs, current);
}

/******************************************************************************
 * GObject Implementation
 *****************************************************************************/
static void
pidgin_credential_prefs_init(PidginCredentialPrefs *prefs) {
	PurpleCredentialManager *manager = NULL;
	PurpleCredentialProvider *active = NULL;
	GtkCustomSorter *sorter = NULL;
	GtkSortListModel *sorted = NULL;
	GListModel *model = NULL;

	gtk_widget_init_template(GTK_WIDGET(prefs));

	sorter = gtk_custom_sorter_new(pidgin_credential_prefs_sort_rows, NULL,
	                               NULL);

	model = purple_credential_manager_get_default_as_model();
	sorted = gtk_sort_list_model_new(model, GTK_SORTER(sorter));
	gtk_list_box_bind_model(GTK_LIST_BOX(prefs->credential_list),
	                        G_LIST_MODEL(sorted),
	                        (GtkListBoxCreateWidgetFunc)pidgin_credential_prefs_create_row,
	                        prefs->credential_list, NULL);

	manager = purple_credential_manager_get_default();
	g_signal_connect_object(manager, "active-changed",
	                        G_CALLBACK(pidgin_credential_prefs_active_provider_changed_cb),
	                        prefs, 0);

	active = purple_credential_manager_get_active(manager);
	if(active != NULL) {
		pidgin_credential_prefs_set_active_provider(prefs, active);
	}
}

static void
pidgin_credential_prefs_class_init(PidginCredentialPrefsClass *klass) {
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);

	gtk_widget_class_set_template_from_resource(
	    widget_class,
	    "/im/pidgin/Pidgin3/Prefs/credentials.ui"
	);

	gtk_widget_class_bind_template_child(widget_class, PidginCredentialPrefs,
	                                     credential_list);
	gtk_widget_class_bind_template_callback(widget_class,
	                                        pidgin_credential_prefs_list_row_activated_cb);
}

/******************************************************************************
 * API
 *****************************************************************************/
GtkWidget *
pidgin_credential_prefs_new(void) {
	return g_object_new(PIDGIN_TYPE_CREDENTIAL_PREFS, NULL);
}
