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

#include <birb.h>

#include <adwaita.h>

#include "pidginaccounteditor.h"

#include "pidginprotocolchooser.h"

struct _PidginAccountEditor {
	AdwPreferencesPage parent;

	PurpleAccount *account;

	char *account_name;

	GtkWidget *protocol_chooser;
	PurpleProtocol *protocol;

	gboolean valid;

	GtkSortListModel *weighted_model;
	GtkCustomSorter *weighted_sorter;

	GtkCustomFilter *filtered_filter;
	GtkFilterListModel *filtered_model;

	gboolean show_advanced;
	GtkWidget *settings_group;

	PurpleAccountSettings *account_settings;
};

enum {
	PROP_0,
	PROP_ACCOUNT,
	PROP_ACCOUNT_NAME,
	PROP_ACCOUNT_SETTINGS,
	PROP_PROTOCOL,
	PROP_SHOW_ADVANCED,
	PROP_VALID,
	N_PROPERTIES,
};
static GParamSpec *properties[N_PROPERTIES] = {NULL, };

/******************************************************************************
 * Helpers
 *****************************************************************************/
static void
pidgin_account_editor_set_valid(PidginAccountEditor *editor, gboolean valid) {
	g_return_if_fail(PIDGIN_IS_ACCOUNT_EDITOR(editor));

	if(editor->valid != valid) {
		editor->valid = valid;

		g_object_notify_by_pspec(G_OBJECT(editor), properties[PROP_VALID]);
	}
}

static void
pidgin_account_editor_update_account_settings(PidginAccountEditor *editor) {
	/* We need to clear the account settings when the protocol changes. */
	purple_account_settings_remove_all_settings(editor->account_settings);

	/* If we have a protocol, grab its default settings. */
	if(PURPLE_IS_PROTOCOL(editor->protocol)) {
		PurpleAccountSettings *settings = NULL;

		settings = purple_protocol_get_default_account_settings(editor->protocol);
		purple_account_settings_update_settings(editor->account_settings,
		                                        settings);
		g_clear_object(&settings);
	}

	/* If we have an account and it's the same protocol, we need to update
	 * with the account settings.
	 */
	if(PURPLE_IS_ACCOUNT(editor->account)) {
		PurpleProtocol *account_protocol = NULL;

		account_protocol = purple_account_get_protocol(editor->account);
		if(account_protocol == editor->protocol) {
			PurpleAccountSettings *settings = NULL;

			settings = purple_account_get_settings(editor->account);
			purple_account_settings_update_settings(editor->account_settings,
			                                        settings);
		}
	}
}

static gboolean
pidgin_account_editor_transform_int_to_str(G_GNUC_UNUSED GBinding *binding,
                                           const GValue *from_value,
                                           GValue *to_value,
                                           G_GNUC_UNUSED gpointer data)
{
	char *str = NULL;
	int value = 0;

	value = g_value_get_int(from_value);
	str = g_strdup_printf("%d", value);
	g_value_take_string(to_value, str);

	return TRUE;
}

static gboolean
pidgin_account_editor_transform_str_to_int(G_GNUC_UNUSED GBinding *binding,
                                           const GValue *from_value,
                                           GValue *to_value,
                                           G_GNUC_UNUSED gpointer data)
{
	char *endptr = NULL;
	const char *str = NULL;
	gulong parsed_value = 0;

	str = g_value_get_string(from_value);
	parsed_value = strtoul(str, &endptr, 10);

	if(endptr == str) {
		return FALSE;
	}

	if(parsed_value == ULONG_MAX) {
		if(errno == ERANGE || errno == EINVAL) {
			return FALSE;
		}
	}

	if(parsed_value > G_MAXINT32) {
		return FALSE;
	}

	g_value_set_int(to_value, parsed_value);

	return TRUE;
}

static gboolean
pidgin_account_editor_transform_null_to_empty_str(G_GNUC_UNUSED GBinding *binding,
                                                  const GValue *from_value,
                                                  GValue *to_value,
                                                  G_GNUC_UNUSED gpointer data)
{
	const char *value = NULL;

	value = g_value_get_string(from_value);
	if(value == NULL) {
		g_value_set_string(to_value, "");
	} else {
		g_value_set_string(to_value, value);
	}

	return TRUE;
}

static gboolean
pidgin_account_editor_transform_empty_str_to_null(G_GNUC_UNUSED GBinding *binding,
                                                  const GValue *from_value,
                                                  GValue *to_value,
                                                  G_GNUC_UNUSED gpointer data)
{
	const char *value = NULL;

	value = g_value_get_string(from_value);
	if(birb_str_is_empty(value)) {
		g_value_set_string(to_value, NULL);
	} else {
		g_value_set_string(to_value, value);
	}

	return TRUE;
}

static gboolean
pidgin_account_editor_transform_string_list_active_item_to_index(G_GNUC_UNUSED GBinding *binding,
                                                                 const GValue *from_value,
                                                                 GValue *to_value,
                                                                 gpointer data)
{
	PurpleAccountSettingStringList *setting = data;
	GListModel *model = G_LIST_MODEL(setting);
	const char *active_item = NULL;
	guint n_items = 0;

	active_item = g_value_get_string(from_value);
	if(active_item == NULL) {
		g_value_set_uint(to_value, GTK_INVALID_LIST_POSITION);
		return TRUE;
	}

	n_items = g_list_model_get_n_items(model);
	for(guint i = 0; i < n_items; i++) {
		BirbLocalizedString *str = NULL;
		const char *id = NULL;

		str = g_list_model_get_item(model, i);
		id = birb_localized_string_get_id(str);

		if(birb_str_equal(id, active_item)) {
			g_value_set_uint(to_value, i);

			g_clear_object(&str);

			return TRUE;
		}

		g_clear_object(&str);
	}

	return FALSE;
}

static gboolean
pidgin_account_editor_transform_string_list_index_to_active_item(G_GNUC_UNUSED GBinding *binding,
                                                                 const GValue *from_value,
                                                                 GValue *to_value,
                                                                 gpointer data)
{
	PurpleAccountSettingStringList *setting = data;
	BirbLocalizedString *str = NULL;
	guint index = GTK_INVALID_LIST_POSITION;

	index = g_value_get_uint(from_value);
	if(index >= g_list_model_get_n_items(G_LIST_MODEL(setting))) {
		return FALSE;
	}

	str = g_list_model_get_item(G_LIST_MODEL(setting), index);
	g_value_set_string(to_value, birb_localized_string_get_id(str));
	g_clear_object(&str);

	return TRUE;
}

static GtkWidget *
pidgin_account_editor_create_row(GObject *item, G_GNUC_UNUSED gpointer data) {
	GtkWidget *widget = NULL;
	PurpleAccountSetting *setting = NULL;
	const char *label = NULL;

	setting = PURPLE_ACCOUNT_SETTING(item);
	label = purple_account_setting_get_label(setting);

	if(PURPLE_IS_ACCOUNT_SETTING_BOOLEAN(item)) {
		widget = adw_switch_row_new();
		adw_preferences_row_set_title(ADW_PREFERENCES_ROW(widget), label);
		g_object_bind_property(setting, "value", widget, "active",
		                       G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
	} else if(PURPLE_IS_ACCOUNT_SETTING_INT(item)) {
		widget = adw_entry_row_new();
		adw_preferences_row_set_title(ADW_PREFERENCES_ROW(widget), label);
		adw_entry_row_set_input_purpose(ADW_ENTRY_ROW(widget),
		                                GTK_INPUT_PURPOSE_NUMBER);

		g_object_bind_property_full(setting, "value", widget, "text",
		                            G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
		                            pidgin_account_editor_transform_int_to_str,
		                            pidgin_account_editor_transform_str_to_int,
		                            NULL,
		                            NULL);
	} else if(PURPLE_IS_ACCOUNT_SETTING_STRING(item)) {
		widget = adw_entry_row_new();
		gtk_widget_set_focusable(widget, FALSE);
		adw_preferences_row_set_title(ADW_PREFERENCES_ROW(widget),
		                              purple_account_setting_get_label(PURPLE_ACCOUNT_SETTING(setting)));
		adw_entry_row_set_input_purpose(ADW_ENTRY_ROW(widget),
		                                GTK_INPUT_PURPOSE_FREE_FORM);

		g_object_bind_property_full(setting, "value", widget, "text",
		                            G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
		                            pidgin_account_editor_transform_null_to_empty_str,
		                            pidgin_account_editor_transform_empty_str_to_null,
		                            NULL,
		                            NULL);
	} else  if(PURPLE_IS_ACCOUNT_SETTING_STRING_LIST(item)) {
		GtkExpression *expression = NULL;

		widget = adw_combo_row_new();
		adw_preferences_row_set_title(ADW_PREFERENCES_ROW(widget), label);
		adw_combo_row_set_model(ADW_COMBO_ROW(widget), G_LIST_MODEL(item));

		expression = gtk_property_expression_new(BIRB_TYPE_LOCALIZED_STRING,
		                                         NULL, "label");
		adw_combo_row_set_expression(ADW_COMBO_ROW(widget), expression);
		g_clear_pointer(&expression, gtk_expression_unref);

		g_object_bind_property_full(setting, "active-item", widget, "selected",
		                            G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
		                            pidgin_account_editor_transform_string_list_active_item_to_index,
		                            pidgin_account_editor_transform_string_list_index_to_active_item,
		                            g_object_ref(item),
		                            (GDestroyNotify)g_object_unref);
	}

	if(GTK_IS_WIDGET(widget)) {
		if(purple_account_setting_get_advanced(setting)) {
			gtk_widget_add_css_class(widget, "warning");
		}
	} else {
		char *subtitle = NULL;

		widget = adw_action_row_new();
		gtk_widget_set_focusable(widget, FALSE);

		adw_preferences_row_set_title(ADW_PREFERENCES_ROW(widget), label);

		subtitle = g_strdup_printf(_("Unsupported setting type %s"),
		                           G_OBJECT_TYPE_NAME(item));
		adw_action_row_set_subtitle(ADW_ACTION_ROW(widget), subtitle);
		g_free(subtitle);

		gtk_widget_add_css_class(widget, "error");
	}

	return widget;
}

static gboolean
pidgin_account_editor_filter_advanced(GObject *item, gpointer data) {
	PidginAccountEditor *editor = data;
	PurpleAccountSetting *setting = PURPLE_ACCOUNT_SETTING(item);

	if(purple_account_setting_get_advanced(setting)) {
		return editor->show_advanced;
	}

	return TRUE;
}

static int
pidgin_account_editor_sort_settings(gconstpointer a, gconstpointer b,
                                    G_GNUC_UNUSED gpointer data)
{
	PurpleAccountSetting *setting_a = NULL;
	PurpleAccountSetting *setting_b = NULL;
	int weight_a = 0;
	int weight_b = 0;

	setting_a = PURPLE_ACCOUNT_SETTING((gpointer)a);
	setting_b = PURPLE_ACCOUNT_SETTING((gpointer)b);

	weight_a = purple_account_setting_get_weight(setting_a);
	weight_b = purple_account_setting_get_weight(setting_b);

	return weight_a - weight_b;
}

/******************************************************************************
 * GObject Implementation
 *****************************************************************************/
G_DEFINE_FINAL_TYPE(PidginAccountEditor, pidgin_account_editor,
                    ADW_TYPE_PREFERENCES_PAGE)

static void
pidgin_account_editor_get_property(GObject *obj, guint param_id, GValue *value,
                                   GParamSpec *pspec)
{
	PidginAccountEditor *editor = PIDGIN_ACCOUNT_EDITOR(obj);

	switch(param_id) {
	case PROP_ACCOUNT:
		g_value_set_object(value,
		                   pidgin_account_editor_get_account(editor));
		break;
	case PROP_ACCOUNT_NAME:
		g_value_set_string(value,
		                   pidgin_account_editor_get_account_name(editor));
		break;
	case PROP_ACCOUNT_SETTINGS:
		g_value_set_object(value,
		                   pidgin_account_editor_get_account_settings(editor));
		break;
	case PROP_PROTOCOL:
		g_value_set_object(value,
		                   pidgin_account_editor_get_protocol(editor));
		break;
	case PROP_SHOW_ADVANCED:
		g_value_set_boolean(value,
		                    pidgin_account_editor_get_show_advanced(editor));
		break;
	case PROP_VALID:
		g_value_set_boolean(value,
		                    pidgin_account_editor_get_valid(editor));
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
		break;
	}
}

static void
pidgin_account_editor_set_property(GObject *obj, guint param_id,
                                   const GValue *value, GParamSpec *pspec)
{
	PidginAccountEditor *editor = PIDGIN_ACCOUNT_EDITOR(obj);

	switch(param_id) {
	case PROP_ACCOUNT:
		pidgin_account_editor_set_account(editor,
		                                  g_value_get_object(value));
		break;
	case PROP_ACCOUNT_NAME:
		pidgin_account_editor_set_account_name(editor,
		                                       g_value_get_string(value));
		break;
	case PROP_PROTOCOL:
		pidgin_account_editor_set_protocol(editor,
		                                   g_value_get_object(value));
		break;
	case PROP_SHOW_ADVANCED:
		pidgin_account_editor_set_show_advanced(editor,
		                                        g_value_get_boolean(value));
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
		break;
	}
}

static void
pidgin_account_editor_init(PidginAccountEditor *editor) {
	/* The entry for the account name is bound to the account-name property,
	 * but it doesn't like null's, so we set it to empty string before anything
	 * else happens.
	 */
	pidgin_account_editor_set_account_name(editor, "");

	editor->account_settings = purple_account_settings_new();

	gtk_widget_init_template(GTK_WIDGET(editor));

	gtk_custom_filter_set_filter_func(editor->filtered_filter,
	                                  (GtkCustomFilterFunc)pidgin_account_editor_filter_advanced,
	                                  editor, NULL);
	gtk_custom_sorter_set_sort_func(editor->weighted_sorter,
	                                (GCompareDataFunc)pidgin_account_editor_sort_settings,
	                                NULL,
	                                NULL);
	gtk_sort_list_model_set_model(editor->weighted_model,
	                              G_LIST_MODEL(editor->account_settings));

	adw_preferences_group_bind_model(ADW_PREFERENCES_GROUP(editor->settings_group),
	                                 G_LIST_MODEL(editor->filtered_model),
	                                 (GtkListBoxCreateWidgetFunc)pidgin_account_editor_create_row,
	                                 editor,
	                                 NULL);

	/* Force update the settings via the protocol chooser. */
	pidgin_account_editor_set_protocol(editor,
	                                   pidgin_protocol_chooser_get_protocol(PIDGIN_PROTOCOL_CHOOSER(editor->protocol_chooser)));
}

static void
pidgin_account_editor_finalize(GObject *obj) {
	PidginAccountEditor *editor = PIDGIN_ACCOUNT_EDITOR(obj);

	g_clear_object(&editor->account);
	g_clear_pointer(&editor->account_name, g_free);
	g_clear_object(&editor->account_settings);
	g_clear_object(&editor->protocol);

	G_OBJECT_CLASS(pidgin_account_editor_parent_class)->finalize(obj);
}

static void
pidgin_account_editor_class_init(PidginAccountEditorClass *klass) {
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
	GObjectClass *obj_class = G_OBJECT_CLASS(klass);

	obj_class->finalize = pidgin_account_editor_finalize;
	obj_class->get_property = pidgin_account_editor_get_property;
	obj_class->set_property = pidgin_account_editor_set_property;

	/**
	 * PidginAccountEditor:account:
	 *
	 * The account that this editor is modifying.
	 *
	 * Since: 3.0
	 */
	properties[PROP_ACCOUNT] = g_param_spec_object(
		"account", NULL, NULL,
		PURPLE_TYPE_ACCOUNT,
		G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS |
		G_PARAM_EXPLICIT_NOTIFY);

	/**
	 * PidginAccountEditor:account-name:
	 *
	 * The name of the account.
	 *
	 * Since: 3.0
	 */
	properties[PROP_ACCOUNT_NAME] = g_param_spec_string(
		"account-name", NULL, NULL,
		NULL,
		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);

	/**
	 * PidginAccountEditor:account-settings:
	 *
	 * The account settings that are currently being edited.
	 *
	 * Since: 3.0
	 */
	properties[PROP_ACCOUNT_SETTINGS] = g_param_spec_object(
		"account-settings", NULL, NULL,
		PURPLE_TYPE_ACCOUNT_SETTINGS,
		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);

	/**
	 * PidginAccountEditor:protocol:
	 *
	 * The selected protocol in the editor.
	 *
	 * Since: 3.0
	 */
	properties[PROP_PROTOCOL] = g_param_spec_object(
		"protocol", NULL, NULL,
		PURPLE_TYPE_PROTOCOL,
		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);

	/**
	 * PidginAccountEditor:show-advanced:
	 *
	 * Whether or not advanced settings should be shown.
	 *
	 * Since: 3.0
	 */
	properties[PROP_SHOW_ADVANCED] = g_param_spec_boolean(
		"show-advanced", NULL, NULL,
		FALSE,
		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);

	/**
	 * PidginAccountEditor:valid:
	 *
	 * Whether or not the account settings are valid and it is okay to save the
	 * account.
	 *
	 * Since: 3.0
	 */
	properties[PROP_VALID] = g_param_spec_boolean(
		"valid", NULL, NULL,
		FALSE,
		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);

	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);

	gtk_widget_class_set_template_from_resource(widget_class,
	                                            "/im/pidgin/Pidgin3/Accounts/editor.ui");

	gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
	                                     protocol_chooser);
	gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
	                                     weighted_model);
	gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
	                                     weighted_sorter);
	gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
	                                     filtered_filter);
	gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
	                                     filtered_model);
	gtk_widget_class_bind_template_child(widget_class, PidginAccountEditor,
	                                     settings_group);
}

/******************************************************************************
 * API
 *****************************************************************************/
GtkWidget *
pidgin_account_editor_new(PurpleAccount *account) {
	return g_object_new(PIDGIN_TYPE_ACCOUNT_EDITOR, "account", account, NULL);
}

PurpleAccount *
pidgin_account_editor_get_account(PidginAccountEditor *editor) {
	g_return_val_if_fail(PIDGIN_IS_ACCOUNT_EDITOR(editor), NULL);

	return editor->account;
}

void
pidgin_account_editor_set_account(PidginAccountEditor *editor,
                                  PurpleAccount *account)
{
	PurpleProtocol *protocol = NULL;
	GObject *obj = NULL;
	const char *account_name = "";

	g_return_if_fail(PIDGIN_IS_ACCOUNT_EDITOR(editor));

	if(!g_set_object(&editor->account, account)) {
		return;
	}

	if(PURPLE_IS_ACCOUNT(account)) {
		account_name = purple_account_get_name(editor->account);
		protocol = purple_account_get_protocol(editor->account);
	}

	obj = G_OBJECT(editor);
	g_object_freeze_notify(obj);
	pidgin_account_editor_set_account_name(editor, account_name);
	pidgin_account_editor_set_protocol(editor, protocol);
	g_object_notify_by_pspec(obj, properties[PROP_ACCOUNT]);
	g_object_thaw_notify(obj);

	pidgin_account_editor_update_account_settings(editor);
}

gboolean
pidgin_account_editor_get_valid(PidginAccountEditor *editor) {
	g_return_val_if_fail(PIDGIN_IS_ACCOUNT_EDITOR(editor), FALSE);

	return editor->valid;
}

const char *
pidgin_account_editor_get_account_name(PidginAccountEditor *editor) {
	g_return_val_if_fail(PIDGIN_IS_ACCOUNT_EDITOR(editor), NULL);

	return editor->account_name;
}

PurpleAccountSettings *
pidgin_account_editor_get_account_settings(PidginAccountEditor *editor) {
	g_return_val_if_fail(PIDGIN_IS_ACCOUNT_EDITOR(editor), NULL);

	return editor->account_settings;
}

PurpleProtocol *
pidgin_account_editor_get_protocol(PidginAccountEditor *editor) {
	g_return_val_if_fail(PIDGIN_IS_ACCOUNT_EDITOR(editor), NULL);

	return editor->protocol;
}

gboolean
pidgin_account_editor_get_show_advanced(PidginAccountEditor *editor) {
	g_return_val_if_fail(PIDGIN_IS_ACCOUNT_EDITOR(editor), FALSE);

	return editor->show_advanced;
}

void
pidgin_account_editor_save(PidginAccountEditor *editor) {
	PurpleAccountSettings *settings = NULL;
	const char *protocol_id = NULL;
	gboolean created = FALSE;

	g_return_if_fail(PIDGIN_IS_ACCOUNT_EDITOR(editor));
	g_return_if_fail(editor->valid == TRUE);

	/* Grab the protocol id. */
	protocol_id = purple_protocol_get_id(editor->protocol);

	if(!PURPLE_IS_ACCOUNT(editor->account)) {
		/* If we don't have an account, create it. */
		editor->account = purple_account_new(editor->account_name,
		                                     protocol_id);
		created = TRUE;
	} else {
		/* If we do have an account, set its protocol id and account name. */
		purple_account_set_protocol_id(editor->account, protocol_id);
		purple_account_set_name(editor->account, editor->account_name);
	}

	/* Apply the settings. */
	settings = purple_account_get_settings(editor->account);
	purple_account_settings_remove_all_settings(settings);
	purple_account_settings_update_settings(settings,
	                                        editor->account_settings);

	/* If the account was created, enable it and add it to the manager now that
	 * its settings have been applied.
	 */
	if(created) {
		PurpleAccountManager *manager = NULL;

		purple_account_set_enabled(editor->account, TRUE);

		manager = purple_core_get_account_manager(purple_core_get_default());
		purple_account_manager_add(manager, editor->account);
	}
}

void
pidgin_account_editor_set_account_name(PidginAccountEditor *editor,
                                       const char *account_name)
{
	g_return_if_fail(PIDGIN_IS_ACCOUNT_EDITOR(editor));

	if(g_set_str(&editor->account_name, account_name)) {
		GObject *obj = G_OBJECT(editor);

		g_object_freeze_notify(obj);
		g_object_notify_by_pspec(obj, properties[PROP_ACCOUNT_NAME]);

		pidgin_account_editor_set_valid(editor,
		                                !birb_str_is_empty(editor->account_name));

		g_object_thaw_notify(obj);
	}
}

void
pidgin_account_editor_set_protocol(PidginAccountEditor *editor,
                                   PurpleProtocol *protocol)
{
	g_return_if_fail(PIDGIN_IS_ACCOUNT_EDITOR(editor));

	if(g_set_object(&editor->protocol, protocol)) {
		pidgin_account_editor_update_account_settings(editor);

		g_object_notify_by_pspec(G_OBJECT(editor), properties[PROP_PROTOCOL]);
	}
}

void
pidgin_account_editor_set_show_advanced(PidginAccountEditor *editor,
                                        gboolean show_advanced)
{
	g_return_if_fail(PIDGIN_IS_ACCOUNT_EDITOR(editor));

	if(editor->show_advanced != show_advanced) {
		editor->show_advanced = show_advanced;

		g_object_notify_by_pspec(G_OBJECT(editor),
		                         properties[PROP_SHOW_ADVANCED]);

		if(editor->show_advanced) {
			gtk_filter_changed(GTK_FILTER(editor->filtered_filter),
			                   GTK_FILTER_CHANGE_LESS_STRICT);
		} else {
			gtk_filter_changed(GTK_FILTER(editor->filtered_filter),
			                   GTK_FILTER_CHANGE_MORE_STRICT);
		}
	}
}
