/*
 *
 *  D-Bus++ - C++ bindings for D-Bus
 *
 *  Copyright (C) 2005-2007  Paolo Durante <shackan@gmail.com>
 *
 *
 *  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 <dbus-c++/dispatcher.h>

#include <dbus/dbus.h>

#include "dispatcher_p.h"
#include "server_p.h"
#include "connection_p.h"

DBus::Dispatcher* DBus::default_dispatcher = NULL;

using namespace DBus;

Timeout::Timeout( Timeout::Internal* i )
: _int(i)
{
	dbus_timeout_set_data((DBusTimeout*)i, this, NULL);
}

int Timeout::interval() const
{
	return dbus_timeout_get_interval((DBusTimeout*)_int);
}

bool Timeout::enabled() const
{
	return dbus_timeout_get_enabled((DBusTimeout*)_int);
}

bool Timeout::handle()
{
	return dbus_timeout_handle((DBusTimeout*)_int);
}

/*
*/

Watch::Watch( Watch::Internal* i )
: _int(i)
{
	dbus_watch_set_data((DBusWatch*)i, this, NULL);
}

int Watch::descriptor() const
{
    return dbus_watch_get_fd((DBusWatch*)_int);
//	return dbus_watch_get_unix_fd((DBusWatch*)_int);
}

int Watch::flags() const
{
	return dbus_watch_get_flags((DBusWatch*)_int);
}

bool Watch::enabled() const
{
	return dbus_watch_get_enabled((DBusWatch*)_int);
}

bool Watch::handle( int flags )
{
	return dbus_watch_handle((DBusWatch*)_int, flags);
}

/*
*/

dbus_bool_t Dispatcher::Private::on_add_watch( DBusWatch* watch, void* data )
{
	Dispatcher* d = static_cast<Dispatcher*>(data);

	Watch::Internal* w = reinterpret_cast<Watch::Internal*>(watch);

	d->add_watch(w);

	return true;
}

void Dispatcher::Private::on_rem_watch( DBusWatch* watch, void* data )
{
	Dispatcher* d = static_cast<Dispatcher*>(data);

	Watch* w = static_cast<Watch*>(dbus_watch_get_data(watch));

	d->rem_watch(w);
}

void Dispatcher::Private::on_toggle_watch( DBusWatch* watch, void* data )
{
	Watch* w = static_cast<Watch*>(dbus_watch_get_data(watch));

	w->toggle();
}

dbus_bool_t Dispatcher::Private::on_add_timeout( DBusTimeout* timeout, void* data )
{
	Dispatcher* d = static_cast<Dispatcher*>(data);

	Timeout::Internal* t = reinterpret_cast<Timeout::Internal*>(timeout);

	d->add_timeout(t);

	return true;
}

void Dispatcher::Private::on_rem_timeout( DBusTimeout* timeout, void* data )
{
	Dispatcher* d = static_cast<Dispatcher*>(data);

	Timeout* t = static_cast<Timeout*>(dbus_timeout_get_data(timeout));

	d->rem_timeout(t);
}

void Dispatcher::Private::on_toggle_timeout( DBusTimeout* timeout, void* data )
{
	Timeout* t = static_cast<Timeout*>(dbus_timeout_get_data(timeout));

	t->toggle();
}

void Dispatcher::queue_connection( Connection::Private* cp )
{
	_pending_queue.push_back(cp);
}

void Dispatcher::dispatch_pending()
{
	while(_pending_queue.size() > 0)
	{
		Connection::PrivatePList::iterator i, j;
		
		i = _pending_queue.begin();

		while(i != _pending_queue.end())
		{
			j = i; 
			
			++j;

			if((*i)->do_dispatch())
				_pending_queue.erase(i);

			i = j;
		}
	}
}

#ifdef DBUS_HAS_THREADS_INIT_DEFAULT
void DBus::_init_threading()
{
	dbus_threads_init_default();
}
#endif//DBUS_HAS_THREADS_INIT_DEFAULT

void DBus::_init_threading(
	MutexNewFn m1,
	MutexFreeFn m2,
	MutexLockFn m3,
	MutexUnlockFn m4,
	CondVarNewFn c1,
	CondVarFreeFn c2,
	CondVarWaitFn c3,
	CondVarWaitTimeoutFn c4,
	CondVarWakeOneFn c5,
	CondVarWakeAllFn c6
)
{
#ifndef DBUS_HAS_RECURSIVE_MUTEX
	DBusThreadFunctions functions = {
		DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
		DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
		DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
		DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
		DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
		DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
		DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
		DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
		DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
		DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
		(DBusMutexNewFunction) m1,
		(DBusMutexFreeFunction) m2,
		(DBusMutexLockFunction) m3,
		(DBusMutexUnlockFunction) m4,
		(DBusCondVarNewFunction) c1,
		(DBusCondVarFreeFunction) c2,
		(DBusCondVarWaitFunction) c3,
		(DBusCondVarWaitTimeoutFunction) c4,
		(DBusCondVarWakeOneFunction) c5,
		(DBusCondVarWakeAllFunction) c6
	};
#else
	DBusThreadFunctions functions = {
		DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK |
		DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK |
		DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK |
		DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK |
		DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
		DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
		DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
		DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
		DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
		DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
		0, 0, 0, 0,
		(DBusCondVarNewFunction) c1,
		(DBusCondVarFreeFunction) c2,
		(DBusCondVarWaitFunction) c3,
		(DBusCondVarWaitTimeoutFunction) c4,
		(DBusCondVarWakeOneFunction) c5,
		(DBusCondVarWakeAllFunction) c6,
		(DBusRecursiveMutexNewFunction) m1,
		(DBusRecursiveMutexFreeFunction) m2,
		(DBusRecursiveMutexLockFunction) m3,
		(DBusRecursiveMutexUnlockFunction) m4
	};
#endif//DBUS_HAS_RECURSIVE_MUTEX
	dbus_threads_init(&functions);
}
