/*
 * libsyncml - A syncml protocol implementation
 * Copyright (C) 2008  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 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 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 */

#include "../syncml.h"
#include "../syncml_internals.h"
#include "data_sync_devinf.h"
#include "libsyncml/sml_error_internals.h"

static gboolean _prepare(GSource *source, gint *timeout_)
{
	smlTrace(TRACE_INTERNAL, "%s(%p, %p)", __func__, source, timeout_);
        *timeout_ = 50;
        return FALSE;
}

static gboolean _check(GSource *source)
{
	SmlDataSyncObject *dsObject = *((SmlDataSyncObject **)(source + 1));

	GList *o = dsObject->datastores;
	for (; o; o = o->next)
	{
		SmlDataSyncDatastore *datastore = o->data;
		if (datastore->session && smlDsSessionCheck(datastore->session))
			return TRUE;
	}

	return smlManagerCheck(dsObject->manager);
}

static gboolean _dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
{
	smlTrace(TRACE_INTERNAL, "%s(%p, %p, %p)", __func__, source, callback, user_data);
	SmlDataSyncObject *dsObject = user_data;

	GList *o = dsObject->datastores;
	for (; o; o = o->next)
	{
		SmlDataSyncDatastore *datastore = o->data;
		if (datastore->session)
			smlDsSessionDispatch(datastore->session);
	}

	smlManagerDispatch(dsObject->manager);
	return TRUE;
}

SmlBool smlDataSyncLoopStart(SmlDataSyncObject *dsObject, SmlError **error)
{
	smlTrace(TRACE_ENTRY, "%s", __func__);
	CHECK_ERROR_REF

	/* prepare function */

	dsObject->functions = smlTryMalloc0(sizeof(GSourceFuncs), error);
	if (!dsObject->functions)
		goto error;

	dsObject->functions->prepare = _prepare;
	dsObject->functions->check = _check;
	dsObject->functions->dispatch = _dispatch;
	dsObject->functions->finalize = NULL;

	/* prepare context and thread */

	dsObject->context = g_main_context_new();
	if (!dsObject->context)
		goto error;
	dsObject->thread = smlThreadNew(dsObject->context, error);
	if (!dsObject->thread)
		goto error;
	smlThreadStart(dsObject->thread);

	/* prepare source for thread's main loop */

	dsObject->source = g_source_new(dsObject->functions, sizeof(GSource) + sizeof(SmlDataSyncObject *));
	SmlDataSyncObject **ptr = (SmlDataSyncObject **)(dsObject->source + 1);
	*ptr = dsObject;
	g_source_set_callback(dsObject->source, NULL, dsObject, NULL);
	g_source_attach(dsObject->source, dsObject->context);
	g_main_context_ref(dsObject->context);
	
	smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
	return TRUE;
error:
	smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
	return FALSE;
}

void smlDataSyncLoopStop(SmlDataSyncObject *dsObject)
{
	smlTrace(TRACE_ENTRY, "%s", __func__);

	/* stop thread */
	smlThreadStop(dsObject->thread);
	smlThreadFree(dsObject->thread);
	dsObject->thread = NULL;

	/* detach source */
	g_source_unref(dsObject->source);
	dsObject->source = NULL;

	/* free context */
	g_main_context_unref(dsObject->context);
	dsObject->context = NULL;

	/* free functions */
	smlSafeFree((gpointer *)&(dsObject->functions));
	dsObject->functions = NULL;

	smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
}

