/*
 * Copyright (C) Birb Developers
 *
 * Birb is the legal property of its developers, whose names are too numerous
 * to list here. Please refer to the AUTHORS file distributed with this source
 * distribution
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 *
 * This library 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 Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, see <https://www.gnu.org/licenses/>.
 */

#include "birbmenu.h"

/******************************************************************************
 * Helpers
 *****************************************************************************/
static void
birb_menu_populate_dynamic_targets_func(GMenuModel *model, int index,
                                        gpointer data)
{
	GHashTable *table = data;
	char *property = NULL;

	g_return_if_fail(G_IS_MENU(model));

	if(g_menu_model_get_item_attribute(model, index,
	                                   BIRB_MENU_ATTRIBUTE_DYNAMIC_TARGET,
	                                   "s", &property))
	{
		const char *value;

		value = g_hash_table_lookup(table, property);
		g_free(property);

		if(value != NULL) {
			GMenuItem *item = NULL;

			item = g_menu_item_new_from_model(model, index);
			g_menu_item_set_attribute(item, G_MENU_ATTRIBUTE_TARGET, "s",
			                          value);

			g_menu_remove(G_MENU(model), index);
			g_menu_insert_item(G_MENU(model), index, item);
			g_object_unref(item);
		}
	}
}

static void
birb_menu_copy_helper(GMenuModel *source, GMenu *destination) {
	int index = 0;

	for(index = 0; index < g_menu_model_get_n_items(source); index++) {
		GMenuItem *item = NULL;
		GMenuAttributeIter *attr_iter = NULL;
		GMenuLinkIter *link_iter = NULL;

		item = g_menu_item_new(NULL, NULL);

		attr_iter = g_menu_model_iterate_item_attributes(source, index);
		while(g_menu_attribute_iter_next(attr_iter)) {
			const char *name = g_menu_attribute_iter_get_name(attr_iter);
			GVariant *value = g_menu_attribute_iter_get_value(attr_iter);

			if(value != NULL) {
				g_menu_item_set_attribute_value(item, name, value);
				g_variant_unref(value);
			}
		}
		g_clear_object(&attr_iter);

		link_iter = g_menu_model_iterate_item_links(source, index);
		while(g_menu_link_iter_next(link_iter)) {
			GMenuModel *link_source = g_menu_link_iter_get_value(link_iter);
			GMenu *link_destination = g_menu_new();

			birb_menu_copy_helper(link_source, link_destination);

			g_menu_item_set_link(item, g_menu_link_iter_get_name(link_iter),
			                     G_MENU_MODEL(link_destination));

			g_clear_object(&link_source);
			g_clear_object(&link_destination);
		}
		g_clear_object(&link_iter);

		g_menu_append_item(destination, item);
		g_clear_object(&item);
	}
}

/******************************************************************************
 * Public API
 *****************************************************************************/
void
birb_menu_walk(GMenuModel *model, BirbMenuWalkFunc func, gpointer data) {
	for(int index = 0; index < g_menu_model_get_n_items(model); index++) {
		GMenuLinkIter *iter = NULL;

		func(model, index, data);

		iter = g_menu_model_iterate_item_links(model, index);
		while(g_menu_link_iter_next(iter)) {
			GMenuModel *link = g_menu_link_iter_get_value(iter);

			birb_menu_walk(link, func, data);

			g_clear_object(&link);
		}

		g_clear_object(&iter);
	}
}

void
birb_menu_populate_dynamic_targetsv(GMenu *menu, GHashTable *properties) {
	g_return_if_fail(G_IS_MENU(menu));
	g_return_if_fail(properties != NULL);

	birb_menu_walk(G_MENU_MODEL(menu),
	               birb_menu_populate_dynamic_targets_func, properties);
}

void
birb_menu_populate_dynamic_targets(GMenu *menu, const char *first_property,
                                   ...)
{
	GHashTable *table = NULL;
	const char *property = NULL, *value = NULL;
	va_list vargs;

	g_return_if_fail(G_IS_MENU(menu));
	g_return_if_fail(first_property != NULL);

	table = g_hash_table_new(g_str_hash, g_str_equal);

	property = first_property;
	va_start(vargs, first_property);

	/* Iterate through the vargs adding values when we find one that isn't
	 * NULL.
	 */
	do {
		value = va_arg(vargs, const char *);
		if(value != NULL) {
			g_hash_table_insert(table, (gpointer)property, (gpointer)value);
		}

		/* After adding the value, see if we have another property. */
		property = va_arg(vargs, const char *);
	} while(property != NULL);

	va_end(vargs);

	birb_menu_populate_dynamic_targetsv(menu, table);

	g_hash_table_unref(table);
}

GMenu *
birb_menu_copy(GMenuModel *model) {
	GMenu *menu = NULL;

	g_return_val_if_fail(G_IS_MENU_MODEL(model), NULL);

	menu = g_menu_new();

	birb_menu_copy_helper(model, menu);

	return menu;
}
