/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/***************************************************************************
 *            kolab-util-contact-cache.c
 *
 *  2011
 *  Copyright  2011 Silvan Marco Fin
 *  <silvan@kernelconcepts.de>
 ****************************************************************************/

/*
 * This program 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 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
 */

/*----------------------------------------------------------------------------*/

#include "kolab-util-contact-cache.h"
#include "kolab-util-contact.h"

#include <libekolabutil/kolab-util-glib.h>

#include <libecal/e-cal.h>

/*----------------------------------------------------------------------------*/

EContact*
kolab_util_contact_cache_get_object (EBookBackendCache *cache,
                                     KolabMailAccess *koma,
                                     const gchar *uri,
                                     const gchar *uid,
                                     gboolean bulk,
                                     GCancellable *cancellable,
                                     GError **error)
{
	const KolabMailHandle *kmh = NULL;
	EContact *econtact = NULL;
	GError *tmp_error = NULL;
	gchar *sourcename = NULL;
	gboolean ok = FALSE;

	g_assert (E_IS_BOOK_BACKEND_CACHE (cache));
	g_assert (KOLAB_IS_MAIL_ACCESS (koma));
	g_assert (uri != NULL);
	g_assert (uid != NULL);
	/* cancellable may be NULL */
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);

	sourcename = kolab_util_backend_get_relative_path_from_uri (uri);

	kmh = kolab_mail_access_get_handle (koma,
	                                    uid,
	                                    sourcename,
	                                    cancellable,
	                                    &tmp_error);
	g_free (sourcename);
	if (kmh == NULL) {
		/* empty object, could be "nothing found" */
		if (tmp_error != NULL) {
			/* this means, something went wrong */
			g_propagate_error (error, tmp_error);
		}
		return NULL;
	}
	ok =  kolab_mail_access_retrieve_handle (koma,
	                                         kmh,
	                                         bulk,
	                                         cancellable,
	                                         &tmp_error);
	if (! ok) {
		g_propagate_error (error, tmp_error);
		return NULL;
	}
	econtact = kolab_mail_handle_get_econtact (kmh);

	return econtact;
} /* kolab_util_contact_cache_get_object () */

gboolean
kolab_util_contact_cache_update_object (EBookBackendCache *cache,
                                        KolabMailAccess *koma,
                                        const gchar *uri,
                                        const gchar *uid,
                                        gboolean bulk,
                                        GCancellable *cancellable,
                                        GError **error)
{
	EContact *tmp_contact = NULL;

	g_assert (E_IS_BOOK_BACKEND_CACHE (cache));
	g_assert (KOLAB_IS_MAIL_ACCESS (koma));
	g_assert (uri != NULL);
	g_assert (uid != NULL);
	/* cancellable may be NULL */
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

	tmp_contact = kolab_util_contact_cache_get_object (cache,
	                                                   koma,
	                                                   uri,
	                                                   uid,
	                                                   bulk,
	                                                   cancellable,
	                                                   error);
	if (tmp_contact != NULL)
		g_object_unref (tmp_contact);
	if (error != NULL)
		return FALSE;
	return TRUE;
}

/**
 * kolab_util_contact_cache_assure_uid_on_econtact:
 * @cache: An EBookBackendCache.
 * @koma: A KolabMailAccess instance.
 * @econtact: An EContact.
 * @uri: An EContact uri string.
 * @bulk: Whether or not this is a mass operation.
 * @cancellable: A cancellation stack.
 * @error: GError placeholder.
 *
 * Sets a new uid to econtact and assures that it is not yet used in @koma.
 *
 * Returns: On Success TRUE is returned.
 */
gboolean
kolab_util_contact_cache_assure_uid_on_econtact (EBookBackendCache *cache,
                                                 KolabMailAccess *koma,
                                                 EContact *econtact,
                                                 const gchar *uri,
                                                 gboolean bulk,
                                                 GCancellable *cancellable,
                                                 GError **error)
{
	EContact *tmp_contact = NULL;
	GError *tmp_error = NULL;
	gchar *uid = NULL;
	KolabSettingsHandler *ksettings = NULL;

	g_assert (E_IS_BOOK_BACKEND_CACHE (cache));
	g_assert (KOLAB_IS_MAIL_ACCESS (koma));
	g_assert (E_IS_CONTACT (econtact));
	g_assert (uri != NULL);
	/* cancellable may be NULL */
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

	ksettings = kolab_mail_access_get_settings_handler (koma);
	if (ksettings == NULL) {
		/* FIXME set a GError */
		return FALSE;
	}
	uid = e_contact_get (econtact, E_CONTACT_UID);
	if (uid == NULL)
		uid = e_cal_component_gen_uid();
	for (;;) {
		tmp_contact = kolab_util_contact_cache_get_object (cache,
		                                                   koma,
		                                                   uri,
		                                                   uid,
		                                                   bulk,
		                                                   cancellable,
		                                                   &tmp_error);
		if (tmp_error != NULL) {
			g_propagate_error (error, tmp_error);
			g_free (uid);
			g_object_unref (ksettings);
			return FALSE;
		}
		if (tmp_contact == NULL) {
			e_contact_set (econtact, E_CONTACT_UID, (gconstpointer) uid);
			g_free (uid);
			break;
		}
		g_object_unref (tmp_contact);
		g_free (uid);
		uid = e_cal_component_gen_uid();
	}
	g_object_unref (ksettings);
	return TRUE;
} /* kolab_util_contact_cache_assure_uid_on_econtact () */

/**
 * kolab_util_contact_cache_update_on_query:
 * @cache: An EBookBackendCache instance.
 * @koma: A KolabMailAccess object.
 * @query: The query string associated with the update operation.
 * @uri: The URI string for access to the @koma object.
 * @cancellable: A cancellation stack.
 * @error: A GError placeholder.
 *
 * Retrieves the changed and not yet cached objects and puts them into the
 * @cache.
 *
 * Returns: TRUE on success.
 */
gboolean
kolab_util_contact_cache_update_on_query (EBookBackendCache *cache,
                                          KolabMailAccess *koma,
                                          const gchar *query,
                                          const gchar *uri,
                                          GCancellable *cancellable,
                                          GError **error)
{
	GList *changed_uids = NULL;
	gchar *sourcename = NULL;
	GError *tmp_error = NULL;

	g_debug ("%s()[%u] called.", __func__, __LINE__);
	sourcename = kolab_util_backend_get_relative_path_from_uri (uri);

	g_assert (E_IS_BOOK_BACKEND_CACHE (cache));
	g_assert (KOLAB_IS_MAIL_ACCESS (koma));
	/* query may be NULL */
	g_assert (uri != NULL);
	/* cancellable may be NULL */
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

	/* First task: Update the BackendCache in case of changes */
	changed_uids = kolab_mail_access_query_changed_uids (koma,
	                                                     sourcename,
	                                                     query,
	                                                     cancellable,
	                                                     &tmp_error);
	if (tmp_error != NULL) {
		g_propagate_error (error, tmp_error);
		return FALSE;
	}
	if (changed_uids != NULL)
		g_debug (" + changed_uids count: %u", g_list_length (changed_uids));
	else
		g_debug (" + changed_uids empty!");
	kolab_util_glib_glist_free (changed_uids);
	return TRUE;
}

GList*
kolab_util_contact_cache_get_contacts (EBookBackendCache *cache,
                                       KolabMailAccess *koma,
                                       const gchar *query,
                                       const gchar *uri,
                                       GCancellable *cancellable,
                                       GError **error)
{
	GList *contact_list = NULL;
	GList *uid_list = NULL;
	GList *it = NULL;
	gchar *sourcename = NULL;
	const KolabMailHandle *kmh = NULL;
	EContact *econtact = NULL;
	gboolean ok = FALSE;
	GError *tmp_error = NULL;
	g_debug ("%s()[%u] called.", __func__, __LINE__);
	sourcename = kolab_util_backend_get_relative_path_from_uri (uri);

	g_assert (E_IS_BOOK_BACKEND_CACHE (cache));
	g_assert (KOLAB_IS_MAIL_ACCESS (koma));
	/* query may be NULL */
	g_assert (uri != NULL);
	/* cancellable may be NULL */
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);

	/* get list of Kolab UIDs */
	uid_list = kolab_mail_access_query_uids (koma, sourcename, query, &tmp_error);
	if (tmp_error != NULL) {
		g_propagate_error (error, tmp_error);
		return NULL;
	}

	/* generate list */
	for (it = g_list_first (uid_list); it != NULL; it = g_list_next (it)) {
		kmh = kolab_mail_access_get_handle (koma,
		                                    (gchar *)it->data,
		                                    sourcename,
		                                    cancellable,
		                                    &tmp_error);
		if (kmh == NULL) {
			g_warning ("%s()[%u]: %s", __func__, __LINE__, tmp_error->message);
			g_error_free (tmp_error);
			tmp_error = NULL;
			continue;
		}
		ok = kolab_mail_access_retrieve_handle (koma,
		                                        kmh,
		                                        TRUE,
		                                        cancellable,
		                                        &tmp_error);
		if (! ok) {
			g_warning ("%s()[%u]: %s", __func__, __LINE__, tmp_error->message);
			g_error_free (tmp_error);
			tmp_error = NULL;
			continue;
		}
		econtact = kolab_mail_handle_get_econtact (kmh);
		if (econtact == NULL) {
			g_warning ("%s()[%u]: %s", __func__, __LINE__, "EContact is NULL");
			continue;
		}
		contact_list = g_list_prepend (contact_list, econtact);
	}

	g_list_free (uid_list);
	return contact_list;
}

/*----------------------------------------------------------------------------*/
