// vim: colorcolumn=80 ts=4 sw=4 linebreak breakindent breakindentopt=shift\:4

#include "gfi-list-entry.h"

/* GLOBALS FOR PROPERTIES */

enum property_types
{
	PROP_LIST_TYPE = 1,
	PROP_INST_REF,
	PROP_APP_XDG_NAME,
	PROP_APP_PRETTY_NAME,
	PROP_APP_DESC,
	PROP_APP_LATEST_VERSION,
	N_PROPERTIES
};

static GParamSpec *properties[N_PROPERTIES];

/* GOBJECT DEFINITION */

struct _GfiListEntry
{
	GObject parent_instance;

	GfiListWidgetType type;
	FlatpakInstalledRef *inst_ref;
	char *app_xdg_name;
	char *app_prettyname;
	char *app_desc;
	char *app_latest_version;
};

G_DEFINE_TYPE (GfiListEntry, gfi_list_entry, G_TYPE_OBJECT)

/* --- */

void
gfi_list_entry_set_list_type (GfiListEntry *self, GfiListWidgetType type)
{
	g_return_if_fail (GFI_IS_LIST_ENTRY (self));

	self->type = type;

	g_object_notify_by_pspec (G_OBJECT(self), properties[PROP_LIST_TYPE]);
}

GfiListWidgetType
gfi_list_entry_get_list_type (GfiListEntry *self)
{
	g_return_val_if_fail (GFI_IS_LIST_ENTRY (self), 0);

	return self->type;
}

static void
update_string_props_from_inst_ref (GfiListEntry *self)
{
	g_autoptr(GBytes) installed_ref_data = NULL;
	g_autoptr(GKeyFile) keyfile = NULL;
	g_autofree char *tmp_prettyname = NULL;

	char *app_prettyname = NULL;
	char *app_xdgname = NULL;
	char *app_desc = NULL;

	installed_ref_data = flatpak_installed_ref_load_metadata (self->inst_ref, NULL, NULL);

	keyfile = g_key_file_new ();
	g_key_file_load_from_bytes (keyfile, installed_ref_data, G_KEY_FILE_NONE, NULL);

	/* See if we have a genuine application and if so, store its name in a 
	 * string. This will be our backup if we can't get the nicer name (see
	 * below).
	 */
	app_xdgname = get_name_from_keyfile (keyfile, KEYFILE_NAME_APPLICATION);

	if (! app_xdgname)
		return;

	/* See if a prettier name exists. */
	app_prettyname = g_strdup (flatpak_installed_ref_get_appdata_name (self->inst_ref));

	/* Try to grab the app description from .desktop file */
	app_desc = app_desc_from_xdg_id (app_xdgname);

	self->app_xdg_name = g_steal_pointer (&app_xdgname);
	self->app_prettyname = g_steal_pointer (&app_prettyname);
	self->app_desc = g_steal_pointer (&app_desc);
}

void
gfi_list_entry_set_inst_ref (GfiListEntry *self, FlatpakInstalledRef *inst_ref)
{
	g_clear_object (&self->inst_ref);

	g_clear_pointer (&self->app_xdg_name, g_free);
	g_clear_pointer (&self->app_prettyname, g_free);
	g_clear_pointer (&self->app_desc, g_free);

	if (! inst_ref)
		goto out;

	self->inst_ref = g_object_ref (inst_ref);

	update_string_props_from_inst_ref (self);

out:
	g_object_notify_by_pspec (G_OBJECT(self), properties[PROP_INST_REF]);
}

/* transfer none */
FlatpakInstalledRef *
gfi_list_entry_get_inst_ref (GfiListEntry *self)
{
	g_return_val_if_fail (GFI_IS_LIST_ENTRY (self), NULL);

	return self->inst_ref;
}

const char *
gfi_list_entry_get_app_xdg_name (GfiListEntry *self)
{
	g_return_val_if_fail (GFI_IS_LIST_ENTRY (self), NULL);

	return self->app_xdg_name;
}

const char *
gfi_list_entry_get_app_pretty_name (GfiListEntry *self)
{
	g_return_val_if_fail (GFI_IS_LIST_ENTRY (self), NULL);

	return self->app_prettyname;
}

const char *
gfi_list_entry_get_app_desc (GfiListEntry *self)
{
	g_return_val_if_fail (GFI_IS_LIST_ENTRY (self), NULL);

	return self->app_desc;
}

const char *
gfi_list_entry_get_app_latest_version (GfiListEntry *self)
{
	g_return_val_if_fail (GFI_IS_LIST_ENTRY (self), NULL);

	return self->app_latest_version;
}

void
gfi_list_entry_set_app_latest_version (GfiListEntry *self, const char *app_latest_version)
{
	g_return_if_fail (GFI_IS_LIST_ENTRY (self));

	g_clear_pointer (&self->app_latest_version, g_free);
	if (app_latest_version)
		self->app_latest_version = g_strdup (app_latest_version);

	g_object_notify_by_pspec (G_OBJECT(self), properties[PROP_APP_LATEST_VERSION]);
}

static void
gfi_list_entry_set_property (GObject *object,
		guint property_id,
		const GValue *value,
		GParamSpec *pspec)
{
	GfiListEntry *self = GFI_LIST_ENTRY(object);

	switch (property_id)
	{
		case PROP_LIST_TYPE:
			gfi_list_entry_set_list_type (self, g_value_get_enum (value));
			break;

		case PROP_INST_REF:
			gfi_list_entry_set_inst_ref (self, g_value_get_object (value));
			break;

		case PROP_APP_LATEST_VERSION:
			gfi_list_entry_set_app_latest_version (self, g_value_get_string (value));
			break;

		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
			break;
	}
}

static void
gfi_list_entry_get_property (GObject *object,
		guint property_id,
		GValue *value,
		GParamSpec *pspec)
{
	GfiListEntry *self = GFI_LIST_ENTRY(object);

	switch (property_id)
	{
		case PROP_LIST_TYPE:
			g_value_set_enum (value, gfi_list_entry_get_list_type (self));
			break;

		case PROP_INST_REF:
			g_value_set_object (value, gfi_list_entry_get_inst_ref (self));
			break;

		case PROP_APP_XDG_NAME:
			g_value_set_string (value, gfi_list_entry_get_app_xdg_name (self));
			break;

		case PROP_APP_PRETTY_NAME:
			g_value_set_string (value, gfi_list_entry_get_app_pretty_name (self));
			break;

		case PROP_APP_DESC:
			g_value_set_string (value, gfi_list_entry_get_app_desc (self));
			break;

		case PROP_APP_LATEST_VERSION:
			g_value_set_string (value, gfi_list_entry_get_app_latest_version (self));
			break;

		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
			break;
	}
}

static void
gfi_list_entry_finalize (GObject *object)
{
	GfiListEntry *self = GFI_LIST_ENTRY(object);

	g_free (self->app_xdg_name);
	g_free (self->app_prettyname);
	g_free (self->app_desc);

	/* Chain up */
	G_OBJECT_CLASS(gfi_list_entry_parent_class)->finalize (object);
}

static void
gfi_list_entry_dispose (GObject *object)
{
	GfiListEntry *self = GFI_LIST_ENTRY(object);

	g_clear_object (&self->inst_ref);

	/* Chain up */
	G_OBJECT_CLASS(gfi_list_entry_parent_class)->dispose (object);
}

static void
gfi_list_entry_init (GfiListEntry *self)
{
}

static void
gfi_list_entry_class_init (GfiListEntryClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS(klass);
	GParamFlags default_flags = G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY;

	object_class->set_property = gfi_list_entry_set_property;
	object_class->get_property = gfi_list_entry_get_property;
	object_class->dispose = gfi_list_entry_dispose;
	object_class->finalize = gfi_list_entry_finalize;

	/* Properties */

	properties[PROP_LIST_TYPE] = g_param_spec_enum ("list-type", NULL, NULL,
			GFI_TYPE_LIST_WIDGET_TYPE,
			GFI_LIST_WIDGET_TYPE_REMOVE,
			default_flags | G_PARAM_READWRITE | G_PARAM_CONSTRUCT);

	properties[PROP_INST_REF] = g_param_spec_object ("inst-ref", NULL, NULL,
			FLATPAK_TYPE_INSTALLED_REF,
			default_flags | G_PARAM_READWRITE | G_PARAM_CONSTRUCT);

	properties[PROP_APP_XDG_NAME] = g_param_spec_string ("app-xdg-name", NULL, NULL,
			NULL,
			default_flags | G_PARAM_READABLE);

	properties[PROP_APP_PRETTY_NAME] = g_param_spec_string ("app-pretty-name", NULL, NULL,
			NULL,
			default_flags | G_PARAM_READABLE);

	properties[PROP_APP_DESC] = g_param_spec_string ("app-desc", NULL, NULL,
			NULL,
			default_flags | G_PARAM_READABLE);

	properties[PROP_APP_LATEST_VERSION] = g_param_spec_string ("app-latest-version", NULL, NULL,
			NULL,
			default_flags | G_PARAM_READWRITE);

	g_object_class_install_properties (object_class, N_PROPERTIES, properties);
}

GfiListEntry *
gfi_list_entry_new (GfiListWidgetType type, FlatpakInstalledRef *inst_ref)
{
	return g_object_new (GFI_TYPE_LIST_ENTRY,
			"list-type", type,
			"inst-ref", inst_ref,
			NULL);
}

G_GNUC_BEGIN_IGNORE_DEPRECATIONS
void
gfi_list_entry_create_app_info_dialog (GfiListEntry *entry, GtkWindow *parent)
{
	GtkWidget *dialog;
	const char *app_xdgname;
	const char *app_prettyname;
	g_autofree char *menu_name = NULL;
	g_autofree char *desc = NULL;

	g_return_if_fail (GFI_IS_LIST_ENTRY (entry));

	app_xdgname = gfi_list_entry_get_app_xdg_name (entry);
	app_prettyname = gfi_list_entry_get_app_pretty_name (entry);
	menu_name = app_name_from_xdg_id (app_xdgname);
	desc = app_desc_from_xdg_id (app_xdgname);

	dialog = gtk_message_dialog_new_with_markup (parent,
			GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
			GTK_MESSAGE_INFO,
			GTK_BUTTONS_CLOSE,
			"<big><b>%s</b></big>\n\n"
			"<b>Application ID:</b> %s\n\n"
			"<b>System name:</b> %s\n\n"
			"<b>Description:</b> %s",
			app_prettyname,
			app_xdgname,
			menu_name,
			desc);

	g_signal_connect (dialog, "response",
			G_CALLBACK(gtk_window_destroy), NULL);

	gtk_window_present (GTK_WINDOW(dialog));
}
G_GNUC_END_IGNORE_DEPRECATIONS
