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

#include <birb.h>

#include "purpledemocontacts.h"

#include "purpledemoresource.h"

/******************************************************************************
 * Helpers
 *****************************************************************************/
static void
purple_demo_contacts_load_contact_icon(PurpleContactInfo *info,
                                       const char *name)
{
	PurpleImage *avatar = NULL;
	GError *error = NULL;
	char *path = NULL;

	path = g_strdup_printf("/im/pidgin/libpurple/protocols/demo/buddy_icons/%s.png",
	                       name);
	avatar = purple_image_new_from_resource(path, &error);

	if(error != NULL) {
		g_message("Failed to load find an icon for %s: %s", path,
		          error->message);

		g_free(path);
		g_clear_error(&error);

		return;
	}

	g_free(path);

	if(PURPLE_IS_IMAGE(avatar)) {
		purple_contact_info_set_avatar(info, avatar);

		g_clear_object(&avatar);
	}
}

static void
purple_demo_contacts_load_contact_person(JsonObject *person_object,
                                         PurpleContactInfo *info)
{
	PurplePerson *person = NULL;
	gboolean new_person = FALSE;
	const char *value = NULL;

	/* If the person has an id, grab it so we can use it when constructing the
	 * person object.
	 */
	if(json_object_has_member(person_object, "id")) {
		value = json_object_get_string_member(person_object, "id");
	}

	/* See if the contact has an existing person. */
	person = purple_contact_info_get_person(info);
	if(PURPLE_IS_PERSON(person)) {
		const char *existing_id = NULL;

		/* If the existing person's id doesn't match the new one, NULL out
		 * person so it'll be recreated with the new id.
		 */
		existing_id = purple_person_get_id(person);
		if(!birb_str_equal(existing_id, value)) {
			person = NULL;
		}
	}

	/* If the person didn't exist or it had a different id, create a new person
	 * with the id.
	 */
	if(!PURPLE_IS_PERSON(person)) {
		person = g_object_new(PURPLE_TYPE_PERSON, "id", value, NULL);
		new_person = TRUE;
	}

	/* Alias */
	if(json_object_has_member(person_object, "alias")) {
		value = json_object_get_string_member(person_object, "alias");
		if(!birb_str_is_empty(value)) {
			purple_person_set_alias(person, value);
		}
	}

	/* Create the link between the person and the contact info. */
	if(new_person) {
		purple_person_add_contact_info(person, info);
		purple_contact_info_set_person(info, person);

		g_clear_object(&person);
	}
}

static void
purple_demo_contacts_load_contact_presence(JsonObject *presence_object,
                                           PurpleContactInfo *info)
{
	PurplePresence *presence = NULL;
	const gchar *value = NULL;

	presence = purple_contact_info_get_presence(info);

	/* Emoji */
	if(json_object_has_member(presence_object, "emoji")) {
		value = json_object_get_string_member(presence_object, "emoji");
		if(!birb_str_is_empty(value)) {
			purple_presence_set_emoji(presence, value);
		}
	}

	/* Idle Time */
	if(json_object_has_member(presence_object, "idle")) {
		GDateTime *now = NULL;
		GDateTime *idle_since = NULL;
		gint64 ivalue = 0;

		ivalue = json_object_get_int_member(presence_object, "idle");

		now = g_date_time_new_now_local();
		idle_since = g_date_time_add_minutes(now, -1 * ivalue);

		purple_presence_set_idle_time(presence, idle_since);

		g_date_time_unref(idle_since);
		g_date_time_unref(now);
	}

	/* Message */
	if(json_object_has_member(presence_object, "message")) {
		value = json_object_get_string_member(presence_object, "message");
		if(!birb_str_is_empty(value)) {
			purple_presence_set_message(presence, value);
		}
	}

	/* Mobile */
	if(json_object_has_member(presence_object, "mobile")) {
		gboolean bvalue = FALSE;
		bvalue = json_object_get_boolean_member(presence_object, "mobile");
		purple_presence_set_mobile(presence, bvalue);
	}

	/* Primitive */
	if(json_object_has_member(presence_object, "primitive")) {
		PurplePresencePrimitive primitive = PURPLE_PRESENCE_PRIMITIVE_OFFLINE;

		value = json_object_get_string_member(presence_object, "primitive");
		if(!birb_str_is_empty(value)) {
			GEnumClass *enum_class = NULL;
			GEnumValue *enum_value = NULL;

			enum_class = g_type_class_ref(PURPLE_TYPE_PRESENCE_PRIMITIVE);
			enum_value = g_enum_get_value_by_nick(enum_class, value);

			if(enum_value != NULL) {
				primitive = enum_value->value;
			}

			g_type_class_unref(enum_class);
		}

		purple_presence_set_primitive(presence, primitive);
	}
}

static PurpleContact *
purple_demo_contacts_load_contact(PurpleAccount *account,
                                  JsonObject *contact_object)
{
	PurpleContact *contact = NULL;
	PurpleContactInfo *info = NULL;
	const char *id = NULL;
	const char *value = NULL;

	/* If we have an id, grab so we can create the contact with it. */
	if(json_object_has_member(contact_object, "id")) {
		id = json_object_get_string_member(contact_object, "id");
	}

	contact = purple_contact_new(account, id);
	info = PURPLE_CONTACT_INFO(contact);

	/* Alias */
	if(json_object_has_member(contact_object, "alias")) {
		value = json_object_get_string_member(contact_object, "alias");
		if(!birb_str_is_empty(value)) {
			purple_contact_info_set_alias(info, value);
		}
	}

	/* Color */
	if(json_object_has_member(contact_object, "color")) {
		value = json_object_get_string_member(contact_object, "color");
		if(!birb_str_is_empty(value)) {
			purple_contact_info_set_color(info, value);
		}
	}

	/* Display Name */
	if(json_object_has_member(contact_object, "display-name")) {
		value = json_object_get_string_member(contact_object, "display-name");
		if(!birb_str_is_empty(value)) {
			purple_contact_info_set_display_name(info, value);

			purple_demo_contacts_load_contact_icon(info, value);
		}
	}

	/* External */
	if(json_object_has_member(contact_object, "external")) {
		gboolean bool_value = FALSE;

		bool_value = json_object_get_boolean_member(contact_object,
		                                            "external");
		purple_contact_info_set_external(info, bool_value);
	}

	/* Load the profile if it exists. */
	if(json_object_has_member(contact_object, "profile")) {
		value = json_object_get_string_member(contact_object, "profile");
		if(!birb_str_is_empty(value)) {
			g_object_set_data_full(G_OBJECT(info), "demo-profile",
			                       g_strdup(value), g_free);
		}
	}

	/* Load the tags. */
	if(json_object_has_member(contact_object, "tags")) {
		PurpleTags *tags = purple_contact_info_get_tags(info);
		JsonArray *array = NULL;
		GList *elements = NULL;

		array = json_object_get_array_member(contact_object, "tags");
		elements = json_array_get_elements(array);
		while(elements != NULL) {
			JsonNode *tag_node = elements->data;
			const char *tag = json_node_get_string(tag_node);

			purple_tags_add(tags, tag);

			elements = g_list_delete_link(elements, elements);
		}
	}

	/* Load the person. */
	if(json_object_has_member(contact_object, "person")) {
		JsonObject *person_object = NULL;

		person_object = json_object_get_object_member(contact_object,
		                                              "person");

		purple_demo_contacts_load_contact_person(person_object, info);
	}

	/* Load the presence. */
	if(json_object_has_member(contact_object, "presence")) {
		JsonObject *presence_object = NULL;

		presence_object = json_object_get_object_member(contact_object,
		                                                "presence");

		purple_demo_contacts_load_contact_presence(presence_object, info);
	}

	return contact;
}

/******************************************************************************
 * Local Exports
 *****************************************************************************/
void
purple_demo_contacts_load(PurpleDemoConnection *connection,
                          PurpleAccount *account)
{
	PurpleContactManager *manager = NULL;
	PurpleContacts *contacts = NULL;
	GError *error = NULL;
	GInputStream *istream = NULL;
	GList *json_contacts = NULL;
	JsonArray *json_array = NULL;
	JsonNode *json_root = NULL;
	JsonParser *parser = NULL;

	/* get a stream to the contacts.json resource */
	istream = g_resource_open_stream(purple_demo_get_resource(),
	                                 "/im/pidgin/libpurple/protocols/demo/contacts.json",
	                                 G_RESOURCE_LOOKUP_FLAGS_NONE, &error);
	if(!G_IS_INPUT_STREAM(istream)) {
		g_critical("%s", error->message);
		g_clear_error(&error);
		return;
	}

	/* create our parser */
	parser = json_parser_new();

	if(!json_parser_load_from_stream(parser, istream, NULL, &error)) {
		g_critical("%s", error->message);
		g_clear_error(&error);
		return;
	}

	json_root = json_parser_get_root(parser);

	manager = purple_contact_manager_get_default();

	/* Load the contacts! */
	json_array = json_node_get_array(json_root);
	json_contacts = json_array_get_elements(json_array);

	contacts = purple_demo_connection_get_contacts(connection);
	while(json_contacts != NULL) {
		PurpleContact *contact = NULL;
		PurplePerson *person = NULL;
		JsonNode *json_node = NULL;
		JsonObject *json_object = NULL;

		json_node = json_contacts->data;
		json_object = json_node_get_object(json_node);

		contact = purple_demo_contacts_load_contact(account, json_object);
		purple_contacts_add(contacts, contact);

		person = purple_contact_info_get_person(PURPLE_CONTACT_INFO(contact));
		if(PURPLE_IS_PERSON(person)) {
			purple_contact_manager_add(manager, contact);
		}

		g_clear_object(&contact);

		json_contacts = g_list_delete_link(json_contacts, json_contacts);
	}

	/* Clean up everything else... */
	g_clear_object(&parser);

	g_input_stream_close(istream, NULL, NULL);
	g_object_unref(istream);
}
