/*
 * Purple - Internet Messaging Library
 * Copyright (C) Pidgin Developers <devel@pidgin.im>
 *
 * 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 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 <glib.h>

#include <birb.h>

#include <purple.h>

/******************************************************************************
 * Tests
 *****************************************************************************/
static void
test_purple_badges_properties(void) {
	PurpleBadges *badges;
	GType item_type = G_TYPE_INVALID;
	guint n_items = 0;

	badges = g_object_new(
		PURPLE_TYPE_BADGES,
		NULL);

	g_object_get(
		badges,
		"item-type", &item_type,
		"n-items", &n_items,
		NULL);

	g_assert_cmpuint(item_type, ==, PURPLE_TYPE_BADGE);
	g_assert_cmpuint(n_items, ==, 0);

	g_assert_finalize_object(badges);
}

static void
test_purple_badges_auto_sort(void) {
	PurpleBadge *high = NULL;
	PurpleBadge *medium = NULL;
	PurpleBadge *low = NULL;
	PurpleBadge *badge = NULL;
	PurpleBadges *badges = NULL;
	gboolean success = FALSE;
	guint counter = 0;
	guint n_items = 0;

	/* This test will add badges with 3 different priorities; high, medium, and
	 * low. medium will be added first, then low, then high. The order will be
	 * checked after each add a counter will be used to see if the
	 * "items-changed" signal was called once per addition.
	 *
	 * Once that's all good, low will be removed, then high, then medium, and
	 * the order and "items-changed" signal counter will be checked as well.
	 */

	badges = purple_badges_new();
	birb_count_list_model_items_changed(G_LIST_MODEL(badges), &counter);

	high = purple_badge_new("high", 1000, "icon-name", "+");
	medium = purple_badge_new("medium", 0, "icon-name", "=");
	low = purple_badge_new("low", -1000, "icon-name", "-");

	/* Start by adding medium. */
	counter = 0;
	success = purple_badges_add_badge(badges, medium);
	g_assert_true(success);
	g_assert_cmpuint(counter, ==, 1);

	n_items = g_list_model_get_n_items(G_LIST_MODEL(badges));
	g_assert_cmpuint(n_items, ==, 1);

	/* Add low. */
	counter = 0;
	success = purple_badges_add_badge(badges, low);
	g_assert_true(success);
	g_assert_cmpuint(counter, ==, 1);

	n_items = g_list_model_get_n_items(G_LIST_MODEL(badges));
	g_assert_cmpuint(n_items, ==, 2);

	badge = g_list_model_get_item(G_LIST_MODEL(badges), 0);
	g_assert_true(badge == medium);
	g_clear_object(&badge);

	badge = g_list_model_get_item(G_LIST_MODEL(badges), 1);
	g_assert_true(badge == low);
	g_clear_object(&badge);

	/* Add High. */
	counter = 0;
	success = purple_badges_add_badge(badges, high);
	g_assert_true(success);
	g_assert_cmpuint(counter, ==, 1);

	n_items = g_list_model_get_n_items(G_LIST_MODEL(badges));
	g_assert_cmpuint(n_items, ==, 3);

	badge = g_list_model_get_item(G_LIST_MODEL(badges), 0);
	g_assert(badge == high);
	g_clear_object(&badge);

	badge = g_list_model_get_item(G_LIST_MODEL(badges), 1);
	g_assert(badge == medium);
	g_clear_object(&badge);

	badge = g_list_model_get_item(G_LIST_MODEL(badges), 2);
	g_assert(badge == low);
	g_clear_object(&badge);

	/* Remove low. */
	counter = 0;
	success = purple_badges_remove_badge(badges, "low");
	g_assert_true(success);
	g_assert_cmpuint(counter, ==, 1);

	n_items = g_list_model_get_n_items(G_LIST_MODEL(badges));
	g_assert_cmpuint(n_items, ==, 2);

	badge = g_list_model_get_item(G_LIST_MODEL(badges), 0);
	g_assert_true(badge == high);
	g_clear_object(&badge);

	badge = g_list_model_get_item(G_LIST_MODEL(badges), 1);
	g_assert_true(badge == medium);
	g_clear_object(&badge);

	/* Remove high. */
	counter = 0;
	success = purple_badges_remove_badge(badges, "high");
	g_assert_true(success);
	g_assert_cmpuint(counter, ==, 1);

	n_items = g_list_model_get_n_items(G_LIST_MODEL(badges));
	g_assert_cmpuint(n_items, ==, 1);

	badge = g_list_model_get_item(G_LIST_MODEL(badges), 0);
	g_assert_true(badge == medium);
	g_clear_object(&badge);

	/* Remove medium. */
	counter = 0;
	success = purple_badges_remove_badge(badges, "medium");
	g_assert_true(success);
	g_assert_cmpuint(counter, ==, 1);

	n_items = g_list_model_get_n_items(G_LIST_MODEL(badges));
	g_assert_cmpuint(n_items, ==, 0);

	/* Cleanup. */
	g_assert_finalize_object(badges);
	g_assert_finalize_object(high);
	g_assert_finalize_object(medium);
	g_assert_finalize_object(low);
}

static void
test_purple_badges_double_add(void) {
	PurpleBadge *badge = NULL;
	PurpleBadges *badges = NULL;
	gboolean success = FALSE;
	guint n_items_counter = 0;
	guint not_empty_counter = 0;

	badges = purple_badges_new();
	birb_count_list_model_items_changed(G_LIST_MODEL(badges),
	                                    &n_items_counter);
	birb_count_property_changed(G_OBJECT(badges), "not-empty",
	                            &not_empty_counter);

	g_assert_false(purple_badges_get_not_empty(badges));

	badge = purple_badge_new("double-add", 0, "icon", "i");

	/* The first add. */
	n_items_counter = 0;
	not_empty_counter = 0;
	success = purple_badges_add_badge(badges, badge);
	g_assert_true(success);
	g_assert_cmpuint(n_items_counter, ==, 1);
	g_assert_cmpuint(not_empty_counter, ==, 1);
	g_assert_true(purple_badges_get_not_empty(badges));

	/* The double add. */
	n_items_counter = 0;
	not_empty_counter = 0;
	success = purple_badges_add_badge(badges, badge);
	g_assert_false(success);
	g_assert_cmpuint(n_items_counter, ==, 0);
	g_assert_cmpuint(not_empty_counter, ==, 0);
	g_assert_true(purple_badges_get_not_empty(badges));

	g_assert_finalize_object(badges);
	g_assert_finalize_object(badge);
}

static void
test_purple_badges_double_remove(void) {
	PurpleBadge *badge = NULL;
	PurpleBadges *badges = NULL;
	gboolean success = FALSE;
	guint n_items_counter = 0;
	guint not_empty_counter = 0;

	badges = purple_badges_new();
	birb_count_property_changed(G_OBJECT(badges), "not-empty",
	                            &not_empty_counter);
	birb_count_list_model_items_changed(G_LIST_MODEL(badges),
	                                    &n_items_counter);

	g_assert_false(purple_badges_get_not_empty(badges));

	badge = purple_badge_new("double-remove", 0, "icon", "i");

	/* The first add. */
	n_items_counter = 0;
	not_empty_counter = 0;
	success = purple_badges_add_badge(badges, badge);
	g_assert_true(success);
	g_assert_cmpuint(n_items_counter, ==, 1);
	g_assert_cmpuint(not_empty_counter, ==, 1);
	g_assert_true(purple_badges_get_not_empty(badges));

	/* The first remove. */
	n_items_counter = 0;
	not_empty_counter = 0;
	success = purple_badges_remove_badge(badges, "double-remove");
	g_assert_true(success);
	g_assert_cmpuint(n_items_counter, ==, 1);
	g_assert_cmpuint(not_empty_counter, ==, 1);

	/* The second remove. */
	n_items_counter = 0;
	not_empty_counter = 0;
	success = purple_badges_remove_badge(badges, "double-remove");
	g_assert_false(success);
	g_assert_cmpuint(n_items_counter, ==, 0);
	g_assert_cmpuint(not_empty_counter, ==, 0);
	g_assert_false(purple_badges_get_not_empty(badges));

	g_assert_finalize_object(badges);
	g_assert_finalize_object(badge);
}

/******************************************************************************
 * Compare Tests
 *****************************************************************************/
static void
test_purple_badges_compare_null__null(void) {
	int result = 0;

	result = purple_badges_compare(NULL, NULL);
	g_assert_cmpint(result, ==, 0);
}

static void
test_purple_badges_compare_empty__null(void) {
	PurpleBadges *badges = NULL;
	int result = 0;

	badges = purple_badges_new();

	result = purple_badges_compare(badges, NULL);
	g_assert_cmpint(result, <, 0);

	g_assert_finalize_object(badges);
}

static void
test_purple_badges_compare_null__empty(void) {
	PurpleBadges *badges = NULL;
	int result = 0;

	badges = purple_badges_new();

	result = purple_badges_compare(NULL, badges);
	g_assert_cmpint(result, >, 0);

	g_assert_finalize_object(badges);
}

static void
test_purple_badges_compare_empty__empty(void) {
	PurpleBadges *badges1 = NULL;
	PurpleBadges *badges2 = NULL;
	int result = 0;

	badges1 = purple_badges_new();
	badges2 = purple_badges_new();

	result = purple_badges_compare(badges1, badges2);
	g_assert_cmpint(result, ==, 0);

	g_assert_finalize_object(badges1);
	g_assert_finalize_object(badges2);
}

static void
test_purple_badges_compare_single__empty(void) {
	PurpleBadge *badge = NULL;
	PurpleBadges *badges1 = NULL;
	PurpleBadges *badges2 = NULL;
	int result = 0;

	badges1 = purple_badges_new();
	badge = purple_badge_new("test", 1000, "icon", "t");
	purple_badges_add_badge(badges1, badge);
	g_clear_object(&badge);

	badges2 = purple_badges_new();

	result = purple_badges_compare(badges1, badges2);
	g_assert_cmpint(result, <, 0);

	g_assert_finalize_object(badges1);
	g_assert_finalize_object(badges2);
}

static void
test_purple_badges_compare_empty__single(void) {
	PurpleBadge *badge = NULL;
	PurpleBadges *badges1 = NULL;
	PurpleBadges *badges2 = NULL;
	int result = 0;

	badges1 = purple_badges_new();

	badges2 = purple_badges_new();
	badge = purple_badge_new("test", 1000, "icon", "t");
	purple_badges_add_badge(badges2, badge);
	g_clear_object(&badge);

	result = purple_badges_compare(badges1, badges2);
	g_assert_cmpint(result, >, 0);

	g_assert_finalize_object(badges1);
	g_assert_finalize_object(badges2);
}

static void
test_purple_badges_compare_multiple__single__left(void) {
	PurpleBadge *badge = NULL;
	PurpleBadges *badges1 = NULL;
	PurpleBadges *badges2 = NULL;
	int result = 0;

	badges1 = purple_badges_new();
	badge = purple_badge_new("test1", 1, "icon", "t");
	purple_badges_add_badge(badges1, badge);
	g_clear_object(&badge);
	badge = purple_badge_new("test2", 1000, "icon", "t");
	purple_badges_add_badge(badges1, badge);
	g_clear_object(&badge);

	badges2 = purple_badges_new();
	badge = purple_badge_new("test3", 1000, "icon", "t");
	purple_badges_add_badge(badges2, badge);
	g_clear_object(&badge);

	result = purple_badges_compare(badges1, badges2);
	g_assert_cmpint(result, <, 0);

	g_assert_finalize_object(badges1);
	g_assert_finalize_object(badges2);
}

static void
test_purple_badges_compare_multiple__single__right(void) {
	PurpleBadge *badge = NULL;
	PurpleBadges *badges1 = NULL;
	PurpleBadges *badges2 = NULL;
	int result = 0;

	badges1 = purple_badges_new();
	badge = purple_badge_new("test1", 1, "icon", "t");
	purple_badges_add_badge(badges1, badge);
	g_clear_object(&badge);
	badge = purple_badge_new("test2", 2, "icon", "t");
	purple_badges_add_badge(badges1, badge);
	g_clear_object(&badge);

	badges2 = purple_badges_new();
	badge = purple_badge_new("test3", 1000, "icon", "t");
	purple_badges_add_badge(badges2, badge);
	g_clear_object(&badge);

	result = purple_badges_compare(badges1, badges2);
	g_assert_cmpint(result, >, 0);

	g_assert_finalize_object(badges1);
	g_assert_finalize_object(badges2);
}

static void
test_purple_badges_compare_single__multiple__right(void) {
	PurpleBadge *badge = NULL;
	PurpleBadges *badges1 = NULL;
	PurpleBadges *badges2 = NULL;
	int result = 0;

	badges1 = purple_badges_new();
	badge = purple_badge_new("test1", 500, "icon", "t");
	purple_badges_add_badge(badges1, badge);
	g_clear_object(&badge);

	badges2 = purple_badges_new();
	badge = purple_badge_new("test2", 500, "icon", "t");
	purple_badges_add_badge(badges2, badge);
	g_clear_object(&badge);
	badge = purple_badge_new("test3", 1000, "icon", "t");
	purple_badges_add_badge(badges2, badge);
	g_clear_object(&badge);

	result = purple_badges_compare(badges1, badges2);
	g_assert_cmpint(result, >, 0);

	g_assert_finalize_object(badges1);
	g_assert_finalize_object(badges2);
}

static void
test_purple_badges_compare_single__single__equal(void) {
	PurpleBadge *badge = NULL;
	PurpleBadges *badges1 = NULL;
	PurpleBadges *badges2 = NULL;
	int result = 0;

	badges1 = purple_badges_new();
	badge = purple_badge_new("test1", 500, "icon", "t");
	purple_badges_add_badge(badges1, badge);
	g_clear_object(&badge);

	badges2 = purple_badges_new();
	badge = purple_badge_new("test2", 500, "icon", "t");
	purple_badges_add_badge(badges2, badge);
	g_clear_object(&badge);

	result = purple_badges_compare(badges1, badges2);
	g_assert_cmpint(result, ==, 0);

	g_assert_finalize_object(badges1);
	g_assert_finalize_object(badges2);
}

/******************************************************************************
 * Main
 *****************************************************************************/
int
main(int argc, char *argv[]) {
	g_test_init(&argc, &argv, NULL);
	g_test_set_nonfatal_assertions();

	g_test_add_func("/badges/properties", test_purple_badges_properties);
	g_test_add_func("/badges/auto-sort", test_purple_badges_auto_sort);
	g_test_add_func("/badges/double-add", test_purple_badges_double_add);
	g_test_add_func("/badges/double-remove", test_purple_badges_double_remove);

	g_test_add_func("/badges/compare/null--null",
	                test_purple_badges_compare_null__null);
	g_test_add_func("/badges/compare/empty--null",
	                test_purple_badges_compare_empty__null);
	g_test_add_func("/badges/compare/null--empty",
	                test_purple_badges_compare_null__empty);
	g_test_add_func("/badges/compare/empty--empty",
	                test_purple_badges_compare_empty__empty);
	g_test_add_func("/badges/compare/single--empty",
	                test_purple_badges_compare_single__empty);
	g_test_add_func("/badges/compare/empty--single",
	                test_purple_badges_compare_empty__single);
	g_test_add_func("/badges/compare/multiple--single--left",
	                test_purple_badges_compare_multiple__single__left);
	g_test_add_func("/badges/compare/multiple--single--right",
	                test_purple_badges_compare_multiple__single__right);
	g_test_add_func("/badges/compare/single--multiple--right",
	                test_purple_badges_compare_single__multiple__right);
	g_test_add_func("/badges/compare/single--single--equal",
	                test_purple_badges_compare_single__single__equal);

	return g_test_run();
}
