/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/***************************************************************************
 *            kolab-mail-synchonizer.h
 *
 *  Thu Jan 20 11:49:12 2011
 *  Copyright  2011  Christian Hilberg
 *  <hilberg@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
 */

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

/**
 * SECTION: kolab-mail-synchronizer
 * @short_description: PIM data (and metadata) synchronization, conflict resolution
 * @title: KolabMailSynchronizer
 * @section_id:
 * @see_also: #KolabMailAccess, #KolabMailInfoDb, #KolabMailImapClient, #KolabFolderSummary, #KolabMailSummary
 * @stability: unstable
 *
 * This class implements the infrastructure to sync #KolabMailSideCache and
 * #KolabMailImapClient with #KolabMailInfoDb.
 *
 * Presently, the #KolabMailImapClient used within KolabMailAccess maintains
 * a read-only email cache (this is a limitation of the IMAP implementation used),
 * so any (new) Kolab PIM object which cannot be stored directly via #KolabMailImapClient
 * because of offline state (requested by the user or lost server connection)
 * gets stored in #KolabMailSideCache for later sync. The same holds true for
 * IMAP folders.
 *
 * Synchronization actions for KolabMailAccess offline->online transition
 *
 * Initial action
 * <itemizedlist>
 *  <listitem>get all foldernames on server</listitem>
 *  <listitem>foreach folder, get CamelFolderInfo</listitem>
 * </itemizedlist>
 *
 * |[
 *      -----------------------+------------------------------------------------
 *      Folders present in     | Action
 *      SideCache | ImapClient |
 *      -----------------------+------------------------------------------------
 *      -----------------------+------------------------------------------------
 *      X         | X          | none
 *      -----------------------+------------------------------------------------
 *      X         |            | Folder has been deleted on server while
 *                |            | Client was offline.
 *                |            |
 *                |            | SideCache: push unsynced UIDs to server,
 *                |            | delete pushed UIDs, delete now-empty folders
 *                |            |
 *                |            | ImapClient: re-get CamelFolderInfo?
 *                |            | re-fetch pushed UIDs (and data) so IMAPX
 *                |            | offline cache will be updated?
 *                |            |
 *                |            | InfoDb: delete UIDs which resided on
 *                |            | server only. Unset SideCache location bits
 *                |            | for successfully pushed UIDs. Set ImapClient
 *                |            | cache location bit if UID data was re-fetched
 *      -----------------------+------------------------------------------------
 *                | X          | Folder has been created on server while
 *                |            | Client was offline.
 *                |            |
 *                |            | SideCache: none
 *                |            |
 *                |            | ImapClient: none
 *                |            |
 *                |            | InfoDb: insert new UIDs (no data yet,
 *                |            | no cache location bit yet)
 *      -----------------------+------------------------------------------------
 *                |            |
 *                |            | TODO what would be the meaning of this?
 *                |            |      If CamelFolderInfo has the folder,
 *                |            |      we regard it "in the IMAPX cache"
 *                |            |
 *      -----------------------+------------------------------------------------
 *
 *
 *      -----------------------+------------------------------------------------
 *      UIDs present in        | Action
 *      SideCache | ImapClient |
 *      -----------------------+------------------------------------------------
 *      -----------------------+------------------------------------------------
 *      X         | X          | Check whether IMAP UID changed.
 *                |            | If so, we have true sync conflict.
 *                |            | Resolve according to user pref (use server/
 *                |            | use local / use newest / create dupe)
 *                |            |
 *                |            | SideCache: after sync success, delete UID
 *                |            |
 *                |            | ImapClient: if server side UID was
 *                |            | overwritten, delete UID data on server,
 *                |            | push new UID data (new email). Re-fetch
 *                |            | data to get it into IMAPX cache
 *                |            |
 *                |            | InfoDb: unset SideCache location bit
 *      -----------------------+------------------------------------------------
 *      X         |            | PIM object was created in offline mode
 *                |            |
 *                |            | SideCache: after sync success, delete UID
 *                |            |
 *                |            | ImapClient: Re-fetch data to get it
 *                |            | into IMAPX cache
 *                |            |
 *                |            | InfoDb: unset SideCache location bit
 *      -----------------------+------------------------------------------------
 *                |            | New PIM object was created on the server
 *                |            | and has not yet been fetched into IMAPX
 *                |            | offline store
 *                |            |
 *                |            | SideCache: none
 *                |            |
 *                |            | ImapClient: Fetch data to get it
 *                |            | into IMAPX cache
 *                |            |
 *                |            | InfoDb: set ImapClient cache location bit
 *      -----------------------+------------------------------------------------
 * ]|
 */

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

#ifndef _KOLAB_MAIL_SYNCHRONIZER_H_
#define _KOLAB_MAIL_SYNCHRONIZER_H_

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

#include <glib.h>
#include <glib-object.h>
#include <gio/gio.h>

#include "kolab-backend-types.h"
#include "kolab-mail-handle.h"
#include "kolab-mail-imap-client.h"
#include "kolab-mail-info-db.h"
#include "kolab-mail-mime-builder.h"
#include "kolab-mail-side-cache.h"
#include "kolab-settings-handler.h"
#include "kolab-util-backend.h"

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

G_BEGIN_DECLS

#define KOLAB_TYPE_MAIL_SYNCHRONIZER             (kolab_mail_synchronizer_get_type ())
#define KOLAB_MAIL_SYNCHRONIZER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), KOLAB_TYPE_MAIL_SYNCHRONIZER, KolabMailSynchronizer))
#define KOLAB_MAIL_SYNCHRONIZER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), KOLAB_TYPE_MAIL_SYNCHRONIZER, KolabMailSynchronizerClass))
#define KOLAB_IS_MAIL_SYNCHRONIZER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), KOLAB_TYPE_MAIL_SYNCHRONIZER))
#define KOLAB_IS_MAIL_SYNCHRONIZER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), KOLAB_TYPE_MAIL_SYNCHRONIZER))
#define KOLAB_MAIL_SYNCHRONIZER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), KOLAB_TYPE_MAIL_SYNCHRONIZER, KolabMailSynchronizerClass))

typedef struct _KolabMailSynchronizerClass KolabMailSynchronizerClass;
typedef struct _KolabMailSynchronizer KolabMailSynchronizer;

struct _KolabMailSynchronizerClass
{
	GObjectClass parent_class;
};

struct _KolabMailSynchronizer
{
	GObject parent_instance;
};

typedef enum {
	KOLAB_MAIL_SYNCHRONIZER_TRANSACTION_TYPE_INVAL = 0,
	KOLAB_MAIL_SYNCHRONIZER_TRANSACTION_TYPE_STORE,
	KOLAB_MAIL_SYNCHRONIZER_TRANSACTION_TYPE_PUSH,
	KOLAB_MAIL_SYNCHRONIZER_TRANSACTION_TYPE_DELETE,
	KOLAB_MAIL_SYNCHRONIZER_TRANSACTION_LAST_TYPE
} KolabMailSynchronizerTransactionTypeID;

GType kolab_mail_synchronizer_get_type (void) G_GNUC_CONST;

gboolean
kolab_mail_synchronizer_configure (KolabMailSynchronizer *self,
                                   KolabSettingsHandler *ksettings,
                                   KolabMailImapClient *client,
                                   KolabMailInfoDb *infodb,
                                   KolabMailSideCache *sidecache,
                                   KolabMailMimeBuilder *mimebuilder,
                                   GError **err);

gboolean
kolab_mail_synchronizer_bringup (KolabMailSynchronizer *self,
                                 GError **err);

gboolean
kolab_mail_synchronizer_shutdown (KolabMailSynchronizer *self,
                                  GError **err);

KolabMailHandle*
kolab_mail_synchronizer_handle_new_from_infodb (KolabMailSynchronizer *self,
                                                const gchar *uid,
                                                const gchar *foldername,
                                                GError **err);

gboolean
kolab_mail_synchronizer_transaction_prepare (KolabMailSynchronizer *self,
                                             KolabMailAccessOpmodeID opmode,
                                             KolabMailSynchronizerTransactionTypeID ttid,
                                             KolabMailHandle *kmailhandle,
                                             const gchar *foldername,
                                             GHashTable *imap_summaries,
                                             KolabMailInfoDbRecord **record,
                                             GCancellable *cancellable,
                                             GError **err);
gboolean
kolab_mail_synchronizer_transaction_start (KolabMailSynchronizer *self,
                                           KolabMailAccessOpmodeID opmode,
                                           KolabMailSynchronizerTransactionTypeID ttid,
                                           KolabMailHandle *kmailhandle,
                                           const gchar *foldername,
                                           KolabMailInfoDbRecord *record,
                                           GError **err);
gboolean
kolab_mail_synchronizer_transaction_abort (KolabMailSynchronizer *self,
                                           KolabMailAccessOpmodeID opmode,
                                           KolabMailSynchronizerTransactionTypeID ttid,
                                           KolabMailHandle *kmailhandle,
                                           const gchar *foldername,
                                           KolabMailInfoDbRecord *record,
                                           GError **err);
gboolean
kolab_mail_synchronizer_transaction_commit (KolabMailSynchronizer *self,
                                            KolabMailAccessOpmodeID opmode,
                                            KolabMailSynchronizerTransactionTypeID ttid,
                                            KolabMailHandle *kmailhandle,
                                            const gchar *foldername,
                                            KolabMailInfoDbRecord *record,
                                            GError **err);

gboolean
kolab_mail_synchronizer_info_sync (KolabMailSynchronizer *self,
                                   KolabMailAccessOpmodeID opmode,
                                   const gchar *foldername,
                                   GCancellable *cancellable,
                                   GError **err);
gboolean
kolab_mail_synchronizer_full_sync (KolabMailSynchronizer *self,
                                   KolabMailAccessOpmodeID opmode,
                                   const gchar *foldername,
                                   GCancellable *cancellable,
                                   GError **err);

G_END_DECLS

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

#endif /* _KOLAB_MAIL_SYNCHRONIZER_H_ */

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