/* sml_data_sync_data_store_session_internals.c
 *
 * Copyright (C) 2009 Michael Bell <michael.bell@opensync.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 */

#include "sml_data_sync_data_store_session_private.h"

#include "../sml_support.h"
#include "../sml_error_internals.h"

#include "../objects/sml_ds_server.h"

#include "sml_data_sync_data_store_internals.h"
#include "sml_data_sync_change_item_internals.h"
#include "sml_data_sync_defines.h"
#include "sml_data_sync_internals.h"
#include "sml_data_sync_session_internals.h"
#include "data_sync_devinf.h"

G_DEFINE_TYPE (SmlDataSyncDataStoreSession, sml_data_sync_data_store_session, G_TYPE_OBJECT)

static void
sml_data_sync_data_store_session_get_property (GObject    *object,
                                               guint       property_id,
                                               GValue     *value,
                                               GParamSpec *pspec)
{
	switch (property_id) {
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
	}
}

static void
sml_data_sync_data_store_session_set_property (GObject      *object,
                                               guint         property_id,
                                               const GValue *value,
                                               GParamSpec   *pspec)
{
	switch (property_id) {
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
	}
}

static void
sml_data_sync_data_store_session_finalize (GObject *object)
{
	SmlDataSyncDataStoreSession *self = (SmlDataSyncDataStoreSession *) object;

	/* cleanup lists */

	while(self->priv->changes) {
		SmlDataSyncChangeItem *change = self->priv->changes->data;
		self->priv->changes = g_list_remove(self->priv->changes, change);
		g_object_unref(change);
	}

	while(self->priv->mappings) {
		SmlMapItem *mapping = self->priv->mappings->data;
		self->priv->mappings = g_list_remove(self->priv->mappings, mapping);
		g_object_unref(mapping);
	}

	/* cleanup object references */

	if (self->priv->data_store_session) {
		smlDsSessionUnref(self->priv->data_store_session);
		self->priv->data_store_session = NULL;
	}
	if (self->priv->data_store) {
		g_object_unref(self->priv->data_store);
		self->priv->data_store = NULL;
	}
	if (self->priv->data_sync_session) {
		g_object_unref(self->priv->data_sync_session);
		self->priv->data_sync_session = NULL;
	}

	/* cleanup sync anchors */

	if (self->priv->remote_next)
		smlSafeCFree(&(self->priv->remote_next));
	if (self->priv->local_next)
		smlSafeCFree(&(self->priv->local_next));

	G_OBJECT_CLASS (sml_data_sync_data_store_session_parent_class)->finalize (object);
}

static void
sml_data_sync_data_store_session_class_init (SmlDataSyncDataStoreSessionClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);

	g_type_class_add_private (klass, sizeof (SmlDataSyncDataStoreSessionPrivate));

	object_class->get_property = sml_data_sync_data_store_session_get_property;
	object_class->set_property = sml_data_sync_data_store_session_set_property;
	object_class->finalize     = sml_data_sync_data_store_session_finalize;

}

static void
sml_data_sync_data_store_session_init (SmlDataSyncDataStoreSession *self)
{
	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
	                                          SML_TYPE_DATA_SYNC_DATA_STORE_SESSION,
	                                          SmlDataSyncDataStoreSessionPrivate);
}

gboolean
sml_data_sync_data_store_session_dump_anchors (SmlDataSyncDataStoreSession *self,
                                               GError **error)
{
	/* anchor caching is optional */
	SmlDataSyncDataStoreSessionSetAnchorCallback callback = NULL;
	void *userdata = NULL;
	callback = sml_data_sync_data_store_get_set_anchor_callback(self->priv->data_store);
	userdata = sml_data_sync_data_store_get_set_anchor_userdata(self->priv->data_store);
	if (!callback)
		return TRUE;

	/* write new sync anchors */

	if (!callback(self, FALSE, self->priv->local_next, userdata, error))
		return FALSE;
	if (!callback(self, TRUE, self->priv->remote_next, userdata, error))
		return FALSE;

	return TRUE;
}

/* ***************************
 *     BEGIN OF CALLBACKS    *
 * ***************************
 */

void sml_data_sync_data_store_session_mapping_callback (SmlDsSession *dsession, SmlMapItem *item, void *userdata);

/* *************************************** */
/* *****     DsSession Callbacks     ***** */
/* *************************************** */

void
sml_data_sync_data_store_connect_callback (SmlDsSession *dsession,
                                           void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, dsession, userdata);
	smlAssert(dsession);
	smlAssert(userdata);

	GError *error = NULL;

	SmlDataSyncDataStore *datastore = userdata;
	SmlDataSync *datasync = sml_data_sync_data_store_get_data_sync(datastore);

	/* The session is required here. So if the session is missing
	 * then the function has to block here. This is no real problem
	 * because the SESSION_EVENT_NEW must already be in the queue of
	 * the manager object.
	 */
	SmlSession *session = smlDsSessionGetSession(dsession);
	SmlDataSyncSession *data_sync_session = sml_data_sync_get_session(datasync, session, &error);
	if (!data_sync_session)
		goto error;
	SmlDataSyncDataStoreSession *self = NULL;
	self = sml_data_sync_session_get_data_store_session(data_sync_session, datastore, &error);
	smlTrace(TRACE_INTERNAL, "%s: self ::= %p", __func__, self);
	if (!self)
		goto error;

	/* set callbacks if the DsSession was not ready before */
	if (!self->priv->data_store_session || self->priv->data_store_session != dsession)
	{
		smlTrace(TRACE_INTERNAL, "%s: should be an OMA DS server", __func__);
		smlAssert(sml_data_sync_get_alert_callback(datasync));
		self->priv->data_store_session = dsession;
		smlDsSessionGetAlert(self->priv->data_store_session, sml_data_sync_get_alert_callback(datasync), self);
		if (sml_data_sync_data_store_get_change_callback(datastore)) {
			smlDsSessionGetSync(self->priv->data_store_session, sml_data_sync_data_store_session_sync_callback, self);
			smlDsSessionGetChanges(self->priv->data_store_session, sml_data_sync_data_store_session_change_callback, self);
			smlDsSessionGetMapping(self->priv->data_store_session, sml_data_sync_data_store_session_mapping_callback, self);
		}
		smlDsSessionRef(dsession);
	}

	smlTrace(TRACE_EXIT, "%s", __func__);
	return;
error:
	sml_data_sync_session_send_event(data_sync_session, NULL, SML_DATA_SYNC_SESSION_EVENT_ERROR, error);
	smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, error->message);
	g_error_free(error);
}

/* *********************************** */
/* *****     Alert Callbacks     ***** */
/* *********************************** */

void
sml_data_sync_data_store_session_alert_status_callback (SmlSession *session,
                                                        SmlStatus *status,
                                                        void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata);

	SmlDataSyncDataStoreSession *self = userdata;

	/* If we talk as an OMA DS client with server like an OCS
	 * then it can happen that this server denies the alert
	 * because of an internal problem.
	 * Example OCS: If there is an error inside of an SyncML session
	 *              then you must wait a configured time before you
	 *              can again sucessfully connect this server.
	 *              Typically the server responds with error 503.
	 */
	unsigned int code = smlStatusGetCode(status);
	if (code >= 300 && code != SML_ERROR_REQUIRE_REFRESH)
	{
		/* This is an error. */
		GError *error = NULL;
		g_set_error(&error, SML_ERROR, code,
			"The alert response signals an error - %d.", code);
		sml_data_sync_session_send_event (self->priv->data_sync_session, NULL,
		                                  SML_DATA_SYNC_SESSION_EVENT_ERROR,
		                                  error);
		smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, error->message);
		g_error_free(error);
	} else {
		smlTrace(TRACE_EXIT, "%s", __func__);
	}
}

/* ********************************** */
/* *****     Sync Callbacks     ***** */
/* ********************************** */

void
sml_data_sync_data_store_session_sync_callback (SmlDsSession *dsession,
                                                gsize numchanges,
                                                void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %i, %p)", __func__, dsession, numchanges, userdata);
	SmlDataSyncDataStoreSession *session = userdata;
	GError *error = NULL;

	/* If the device information was not sent together with the
	 * alerts and it was not cached then the device information
	 * can be received together with the sync command(s).
	 * This can happen with OMA DS clients and servers.
	 */
	if (!sml_data_sync_dev_inf_manage_session(session->priv->data_sync_session, FALSE, &error))
		goto error;

	smlTrace(TRACE_EXIT, "%s", __func__);
	return;
error:
	smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, error->message);
	sml_data_sync_session_send_event (session->priv->data_sync_session, NULL,
	                                  SML_DATA_SYNC_SESSION_EVENT_ERROR,
	                                  error);
	g_error_free(error);
}

static void
sml_data_sync_data_store_session_sync_status_callback (SmlSession *session,
                                                       SmlStatus *status,
                                                       void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, session, status, userdata);
	SmlDataSyncDataStoreSession *self = userdata;
	
	if (smlStatusGetClass(status) != SML_ERRORCLASS_SUCCESS)
	{
		// inform user
		smlTrace(TRACE_INTERNAL, "%s: The synchronisation request failed.", __func__);
		smlTrace(TRACE_INTERNAL, "%s: Database => %s", __func__, VA_STRING(sml_location_get_uri(sml_data_sync_data_store_get_local(self->priv->data_store))));
		smlTrace(TRACE_INTERNAL, "%s: Error => %d", __func__, smlStatusGetCode(status));
		if (smlStatusGetCode(status) == SML_ERROR_SERVICE_UNAVAILABLE)
		{
			/* this is a potential Oracle Collaboration Suite */
			/* typical errorcode from OCS if there is something wrong */
			smlTrace(TRACE_INTERNAL,
				"%s: Oracle Collaboration Suite detected.",
				__func__);
			smlTrace(TRACE_INTERNAL,
				"%s: Typical undefined error from OCS (503 - SyncML timeout error).",
				__func__);
			smlTrace(TRACE_INTERNAL,
				"%s: Please wait 5 minutes before retry - default session timeout.",
				__func__);
		}
		// stop session
		// FIXME: this is not available in a clean way today
		// FIXME: we need a session state
		// FIXME: osync must be signalled
		// FIXME: we need a mutex lock on database->env
		// smlSessionEnd(database->env->session, NULL);
		// printf("    Session finished.\n");
		// smlManagerSessionRemove(database->env->manager, database->env->session);
		// smlManagerStop(database->env->manager);
		// smlManagerQuit(database->env->manager);
		// printf("    Manager finished.\n");
		GError *error = NULL;
		g_set_error(&error, SML_ERROR, smlStatusGetCode(status),
			"Sync failed with error %d.",
			smlStatusGetCode(status));
		sml_data_sync_session_send_event(self->priv->data_sync_session,
                                                 NULL,
                                                 SML_DATA_SYNC_SESSION_EVENT_ERROR,
                                                 error);
		smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, error->message);
		g_error_free(error);
	} else {
		smlTrace(TRACE_EXIT, "%s", __func__);
	}
}

/* ************************************ */
/* *****     Change Callbacks     ***** */
/* ************************************ */

gboolean
sml_data_sync_data_store_session_change_callback (SmlDsSession *dsession,
                                                  SmlDataSyncChangeItem *item,
                                                  void *userdata,
                                                  GError **error)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, dsession, item, userdata, error);
	CHECK_ERROR_REF

	SmlDataSyncDataStoreSession *session = userdata;

	smlAssert(item);
	smlAssert(sml_data_sync_change_item_get_action(item));

	SmlDataSyncDataStoreSessionChangeCallback callback = NULL;
	callback = sml_data_sync_data_store_get_change_callback(session->priv->data_store);
	userdata = sml_data_sync_data_store_get_change_userdata(session->priv->data_store);

	/* some mobiles sends replace commands during slow-sync */
	if (session->priv->alert_type == SML_ALERT_SLOW_SYNC &&
	    sml_data_sync_change_item_get_action(item) == SML_CHANGE_REPLACE)
		sml_data_sync_change_item_set_action(item, SML_CHANGE_ADD);

	/* perform callback */
	if (!callback (session, item, userdata, error))
		goto error;

	/* if this is a client then the callback should add a mapping */

	smlTrace(TRACE_EXIT, "%s", __func__);
	return TRUE;
error:
	smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, (*error)->message);
	return FALSE;
}

void
sml_data_sync_data_store_session_change_status_callback (SmlDsSession *dsession,
                                                         SmlStatus *status,
                                                         void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, dsession, status, userdata);
	GError *error = NULL;

	smlAssert(userdata);
	SmlDataSyncChangeItem *change = userdata;
	SmlDataSyncDataStoreSession *self = sml_data_sync_change_item_get_data_store_session(change);

	SmlDataSyncDataStoreSessionChangeStatusCallback callback = NULL;
	callback = sml_data_sync_data_store_get_change_status_callback(self->priv->data_store);
	userdata = sml_data_sync_change_item_get_userdata(change);
	if (!userdata)
		userdata = sml_data_sync_data_store_get_change_status_userdata(self->priv->data_store);

	if (callback && !callback(self, change, smlStatusGetCode(status), userdata, &error))
		goto error;

	smlTrace(TRACE_EXIT, "%s", __func__);
	return;
error:
	sml_data_sync_session_send_event(self->priv->data_sync_session, NULL, SML_DATA_SYNC_SESSION_EVENT_ERROR, error);
	smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, error->message);
	g_error_free(error);
}

/* ********************************* */
/* *****     Map Callbacks     ***** */
/* ********************************* */

void
sml_data_sync_data_store_session_mapping_callback (SmlDsSession *dsession,
                                                   SmlMapItem *item,
                                                   void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, dsession, item, userdata);

	GError *error = NULL;
	SmlDataSyncDataStoreSession *self = userdata;

	smlAssert(self);
	SmlDataSyncDataStoreSessionMappingCallback callback = NULL;
	callback = sml_data_sync_data_store_get_mapping_callback(self->priv->data_store);
	userdata = sml_data_sync_data_store_get_mapping_userdata(self->priv->data_store);
	smlAssert(callback);

	/* perform callback */
	if (!callback(self, item, userdata, &error))
		goto error;

	smlTrace(TRACE_EXIT, "%s", __func__);
	return;
error:
	sml_data_sync_session_send_event(self->priv->data_sync_session, NULL, SML_DATA_SYNC_SESSION_EVENT_ERROR, error);
	smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, error->message);
	g_error_free(error);
}

void
sml_data_sync_data_store_session_mapping_status_callback (SmlSession *session,
                                                          SmlStatus *status,
                                                          void *userdata)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata);

	smlAssert(userdata);
	SmlDataSyncDataStoreSession *self = userdata;

	GError *error = NULL;

	SmlDataSyncDataStoreSessionMappingStatusCallback callback = NULL;
	callback = sml_data_sync_data_store_get_mapping_status_callback(self->priv->data_store);
	userdata = sml_data_sync_data_store_get_mapping_status_userdata(self->priv->data_store);

	if (callback)
	{
		GList *mapping = self->priv->mappings;
		GList *mapping_userdata = self->priv->mappings_userdata;
		for (; mapping; mapping = mapping->next)
		{
			SmlMapItem *item = mapping->data;
			void *muserdata = mapping_userdata->data;
			if (!muserdata)
				muserdata = userdata;

			if (!callback(self, item, smlStatusGetCode(status), muserdata, &error))
				goto error;

			mapping_userdata = mapping_userdata->next;
		}
	}
error:
	if (smlStatusGetClass(status) != SML_ERRORCLASS_SUCCESS || error)
	{
		if (smlStatusGetClass(status) != SML_ERRORCLASS_SUCCESS) {
			if (error)
				g_error_free(error);
			g_set_error(&error, SML_ERROR, smlStatusGetCode(status),
				"Map of datastore %s was rejected with error code %d",
				sml_location_get_uri(sml_data_sync_data_store_get_local(self->priv->data_store)),
				smlStatusGetCode(status));
		}
		sml_data_sync_session_send_event(self->priv->data_sync_session,
		                                 NULL,
                                                 SML_DATA_SYNC_SESSION_EVENT_ERROR,
                                                 error);
		g_error_free(error);
		error = NULL;
	}
	smlTrace(TRACE_EXIT, "%s", __func__);
}

/* ***************************
 *     END OF CALLBACKS    *
 * ***************************
 */

/**
 * sml_data_sync_data_store_session_new:
 *
 * Creates a new instance of #SmlDataSyncDataStoreSession.
 *
 * Return value: the newly created #SmlDataSyncDataStoreSession instance
 */
SmlDataSyncDataStoreSession*
sml_data_sync_data_store_session_new (SmlDataSyncDataStore *datastore,
                                      SmlDataSyncSession *session,
                                      GError **error)
{
	smlTrace(TRACE_ENTRY, "%s (%p, %p, %p)", __func__, datastore, session, error);
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DATA_SYNC_DATA_STORE (datastore), NULL, error, SML_ERROR_GENERIC, "There must be a SmlDataSyncDataStore object.");
	sml_return_val_error_if_fail (SML_IS_DATA_SYNC_SESSION (session), NULL, error, SML_ERROR_GENERIC, "There must be a SmlDataSyncSession object.");

	SmlDataSyncDataStoreSession *self = g_object_new (SML_TYPE_DATA_SYNC_DATA_STORE_SESSION, NULL);

	self->priv->data_store = datastore;
	self->priv->data_sync_session = session;

	smlTrace(TRACE_EXIT, "%s", __func__);
	return self;
}

SmlDataSyncDataStore*
sml_data_sync_data_store_session_get_data_store (SmlDataSyncDataStoreSession *self)
{
	return self->priv->data_store;
}

SmlDataSyncSession*
sml_data_sync_data_store_session_get_data_sync_session (SmlDataSyncDataStoreSession *self)
{
	return self->priv->data_sync_session;
}

void
sml_data_sync_data_store_session_set_session (SmlDataSyncDataStoreSession *self,
                                              SmlDsSession *session)
{
	self->priv->data_store_session = session;
}

/**
 * sml_data_sync_data_store_session_add_change:
 * @self: A #SmlDataSyncDataStoreSession
 *
 * 
 */
gboolean
sml_data_sync_data_store_session_add_change (SmlDataSyncDataStoreSession *self,
                                             SmlDataSyncChangeItem *change,
                                             void *userdata,
                                             GError **error)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, self, change, userdata, error);

	/* check params */
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DATA_SYNC_DATA_STORE_SESSION (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlDataSyncDataStoreSession object.");
	sml_return_val_error_if_fail (SML_IS_DATA_SYNC_CHANGE_ITEM (change), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlDataSyncChangeItem object.");

	/* cache user data for callback */
	sml_data_sync_change_item_set_userdata (change, userdata);

	/* determine the datastore */
	sml_data_sync_change_item_set_data_store_session(change, self);
	if (!sml_data_sync_change_item_set_content_type(change, sml_data_sync_data_store_get_content_type(self->priv->data_store), error))
		goto error;

	/* append change to datastore */
	self->priv->changes = g_list_append(self->priv->changes, change);

	smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
	return TRUE;
error:
	smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, (*error)->message);
	return FALSE;
}

/**
 * sml_data_sync_data_store_session_send_changes:
 * @self: A #SmlDataSyncDataStoreSession
 *
 * 
 */
gboolean
sml_data_sync_data_store_session_send_changes (SmlDataSyncDataStoreSession *self,
                                               GError **error)
{
	smlTrace(TRACE_ENTRY, "%s (%p, %p)", __func__, self, error);
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DATA_SYNC_DATA_STORE_SESSION (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlDataSyncDataStoreSession object.");

	int num = g_list_length(self->priv->changes);

	if (!smlDsSessionSendSync(self->priv->data_store_session,
	                          num,
	                          sml_data_sync_data_store_session_sync_status_callback,
	                          self,
	                          error))
		goto error;
		
	int i = 0;
	for (i = 0; i < num; i++) {
		SmlDataSyncChangeItem *change = g_list_nth_data(self->priv->changes, i);
		if (!smlDsSessionQueueChange(self->priv->data_store_session,
		                             change,
		                             sml_data_sync_data_store_session_change_status_callback,
		                             change,
		                             error))
			goto error;
	}

	if (!smlDsSessionCloseSync(self->priv->data_store_session, error))
		goto error;

	smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
	return TRUE;
error:
	smlTrace(TRACE_EXIT, "%s - FALSE", __func__);
	return FALSE;
}

/**
 * sml_data_sync_data_store_session_add_mapping:
 * @self: A #SmlDataSyncDataStoreSession
 *
 * 
 */
gboolean
sml_data_sync_data_store_session_add_mapping (SmlDataSyncDataStoreSession *self,
                                              SmlMapItem *mapping,
                                              void *userdata,
                                              GError **error)
{
	smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, self, mapping, userdata, error);

	/* check params */
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DATA_SYNC_DATA_STORE_SESSION (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlDataSyncDataStoreSession object.");
	sml_return_val_error_if_fail (SML_IS_MAP_ITEM (mapping), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlMapItem object.");

	/* A map can only be created if a sync from a server was
	 * received. So it makes no sense to cache the mapping.
	 * Therefore the map will be set immediately.
	 */

	if (!smlDsSessionQueueMap(self->priv->data_store_session, mapping, error))
		goto error;

	self->priv->mappings = g_list_append(self->priv->mappings, mapping);
	self->priv->mappings_userdata = g_list_append(self->priv->mappings_userdata, userdata);
	g_object_ref(mapping);

	smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
	return TRUE;
error:
	smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, (*error)->message);
	return FALSE;
}

/**
 * sml_data_sync_data_store_session_send_mappings:
 * @self: A #SmlDataSyncDataStoreSession
 *
 * 
 */
gboolean
sml_data_sync_data_store_session_send_mappings (SmlDataSyncDataStoreSession *self,
                                                GError **error)
{
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DATA_SYNC_DATA_STORE_SESSION (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlDataSyncDataStoreSession object.");

	if (!smlDsSessionCloseMap(self->priv->data_store_session, sml_data_sync_data_store_session_mapping_status_callback, self, error))
		goto error;

	return TRUE;
error:
	return FALSE;
}
/**
 * sml_data_sync_data_store_session_check:
 * @self: A #SmlDataSyncDataStoreSession
 *
 * 
 */
gboolean
sml_data_sync_data_store_session_check (SmlDataSyncDataStoreSession *self)
{
	g_return_val_if_fail (SML_IS_DATA_SYNC_DATA_STORE_SESSION (self), FALSE);
	g_return_val_if_fail (self->priv->data_store_session, FALSE);

	if (smlDsSessionCheck(self->priv->data_store_session))
		return TRUE;
	else
		return FALSE;
}

/**
 * sml_data_sync_data_store_session_dispatch:
 * @self: A #SmlDataSyncDataStoreSession
 *
 * 
 */
gboolean
sml_data_sync_data_store_session_dispatch (SmlDataSyncDataStoreSession *self)
{
	g_return_val_if_fail (SML_IS_DATA_SYNC_DATA_STORE_SESSION (self), FALSE);
	g_return_val_if_fail (self->priv->data_store_session, FALSE);

	smlDsSessionDispatch(self->priv->data_store_session);

	return TRUE;
}

