/*
 * 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 <glib/gi18n.h>

#include "pidginaccountsdisabledmenu.h"

struct _PidginAccountsDisabledMenu {
	GMenuModel parent;

	GListModel *accounts;
};

G_DEFINE_FINAL_TYPE(PidginAccountsDisabledMenu, pidgin_accounts_disabled_menu,
                    G_TYPE_MENU_MODEL)

/******************************************************************************
 * Callbacks
 *****************************************************************************/
static void
pidgin_accounts_disabled_menu_items_changed_cb(GListModel *model,
                                               guint position,
                                               guint removed,
                                               guint added,
                                               gpointer data)
{
	PidginAccountsDisabledMenu *menu = data;
	guint n_items = g_list_model_get_n_items(model);

	if(n_items == 0) {
		/* If every account is enabled, this model will be empty, but we add an
		 * item saying "no disabled accounts".
		 */
		added = 1;
	} else if(n_items == (added - removed) && position == 0) {
		/* In this case, there were no accounts in the model *before*. This
		 * means we need to remove the "no disabled accounts" item that we put
		 * in place when all accounts are enabled.
		 */
		removed = 1;
	}

	g_menu_model_items_changed(G_MENU_MODEL(menu), position, removed, added);
}

/******************************************************************************
 * GMenuModel Implementation
 *****************************************************************************/
static gboolean
pidgin_accounts_disabled_menu_is_mutable(G_GNUC_UNUSED GMenuModel *model) {
	return TRUE;
}

static gboolean
pidgin_accounts_disabled_menu_get_n_items(GMenuModel *model) {
	PidginAccountsDisabledMenu *menu = NULL;

	menu = PIDGIN_ACCOUNTS_DISABLED_MENU(model);

	/* If every account is enabled, we add an item saying "no disabled
	 * accounts", so there's always at least 1.
	 */
	return MAX(1, g_list_model_get_n_items(menu->accounts));
}

static void
pidgin_accounts_disabled_menu_get_item_attributes(GMenuModel *model,
                                                  gint index,
                                                  GHashTable **attributes)
{
	PidginAccountsDisabledMenu *menu = NULL;
	PurpleAccount *account = NULL;
	PurpleProtocol *protocol = NULL;
	GVariant *value = NULL;
	const char *account_name = NULL;

	menu = PIDGIN_ACCOUNTS_DISABLED_MENU(model);

	/* Create our hash table of attributes to return. */
	*attributes = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
	                                    (GDestroyNotify)g_variant_unref);

	/* If we don't have any disabled accounts, just return a single item,
	 * stating as much.
	 */
	if(g_list_model_get_n_items(menu->accounts) == 0) {
		value = g_variant_new_string(_("No disabled accounts"));
		g_hash_table_insert(*attributes, G_MENU_ATTRIBUTE_LABEL,
		                    g_variant_ref_sink(value));

		value = g_variant_new_string("disabled");
		g_hash_table_insert(*attributes, G_MENU_ATTRIBUTE_ACTION,
		                    g_variant_ref_sink(value));

		return;
	}

	account = g_list_model_get_item(menu->accounts, index);
	if(account == NULL) {
		return;
	}

	account_name = purple_account_get_name(account);
	protocol = purple_account_get_protocol(account);
	if(PURPLE_IS_PROTOCOL(protocol)) {
		value = g_variant_new_printf("%s", purple_protocol_get_icon_name(protocol));
		g_hash_table_insert(*attributes, G_MENU_ATTRIBUTE_ICON,
		                    g_variant_ref_sink(value));
	}

	value = g_variant_new_printf("%s", account_name);
	g_hash_table_insert(*attributes, G_MENU_ATTRIBUTE_LABEL,
	                    g_variant_ref_sink(value));

	value = g_variant_new_string("app.enable-account");
	g_hash_table_insert(*attributes, G_MENU_ATTRIBUTE_ACTION,
	                    g_variant_ref_sink(value));

	value = g_variant_new_printf("%s", purple_account_get_id(account));
	g_hash_table_insert(*attributes, G_MENU_ATTRIBUTE_TARGET,
	                    g_variant_ref_sink(value));

	g_clear_object(&account);
}

static void
pidgin_accounts_disabled_menu_get_item_links(G_GNUC_UNUSED GMenuModel *model,
                                             G_GNUC_UNUSED gint index,
                                             GHashTable **links)
{
	*links = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
	                               g_object_unref);
}

/******************************************************************************
 * GObject Implementation
 *****************************************************************************/
static void
pidgin_accounts_disabled_menu_constructed(GObject *obj) {
	PidginAccountsDisabledMenu *menu = PIDGIN_ACCOUNTS_DISABLED_MENU(obj);
	guint count = 0;

	G_OBJECT_CLASS(pidgin_accounts_disabled_menu_parent_class)->constructed(obj);

	count = g_list_model_get_n_items(menu->accounts);
	g_menu_model_items_changed(G_MENU_MODEL(obj), 0, 0, count);
}

static void
pidgin_accounts_disabled_menu_init(PidginAccountsDisabledMenu *menu) {
	PurpleAccountManager *manager = purple_account_manager_get_default();

	menu->accounts = purple_account_manager_get_disabled(manager);
	g_signal_connect_object(menu->accounts, "items-changed",
	                        G_CALLBACK(pidgin_accounts_disabled_menu_items_changed_cb),
	                        menu, G_CONNECT_DEFAULT);
}

static void
pidgin_accounts_disabled_menu_class_init(PidginAccountsDisabledMenuClass *klass) {
	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
	GMenuModelClass *model_class = G_MENU_MODEL_CLASS(klass);

	obj_class->constructed = pidgin_accounts_disabled_menu_constructed;

	model_class->is_mutable = pidgin_accounts_disabled_menu_is_mutable;
	model_class->get_n_items = pidgin_accounts_disabled_menu_get_n_items;
	model_class->get_item_attributes = pidgin_accounts_disabled_menu_get_item_attributes;
	model_class->get_item_links = pidgin_accounts_disabled_menu_get_item_links;
}

/******************************************************************************
 * Public API
 *****************************************************************************/
GMenuModel *
pidgin_accounts_disabled_menu_new(void) {
	return g_object_new(PIDGIN_TYPE_ACCOUNTS_DISABLED_MENU, NULL);
}
