/* $Id: daemon.c 2337 2007-01-11 19:17:30Z nick $
 *
 * Copyright (C) 2006 Christian Hammond <chipx86@chipx86.com>
 * Copyright (C) 2005 John (J5) Palmieri <johnp@redhat.com>
 * Copyright (C) 2006 Nick Schermer <nick@xfce.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <tqsignalmapper.h>
#include <tqevent.h>
#include <tqsize.h>
#include <tqcursor.h>
#include <tqpixmap.h>
#include <tqtimer.h>
#include <knotifyclient.h>
#include <tdeaboutdata.h>
#include <tdecmdlineargs.h>
#include <tdelocale.h>
#include <tdeapplication.h>
#include <kiconloader.h>
#include <tdeglobalsettings.h>
#include <tdepassivepopupstack.h>

#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>

#include "daemon.h"

NotificationContainer* GTKNotifierContainer = NULL;
void real_handleGTKMain();

NotificationContainer::NotificationContainer() : TDEPassivePopupStackContainer() {
	//
}

NotificationContainer::~NotificationContainer() {
	//
}

void NotificationContainer::handleGTKMain() {
	real_handleGTKMain();
}

#undef signals

#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>

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

#include <gdk/gdkx.h>

#include "notificationdaemon-dbus-glue.h"

#define IMAGE_SIZE 48

#define NW_GET_NOTIFY_ID(nw) \
	(GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(nw), "_notify_id")))
#define NW_GET_NOTIFY_SENDER(nw) \
	(g_object_get_data(G_OBJECT(nw), "_notify_sender"))
#define NW_GET_DAEMON(nw) \
	(g_object_get_data(G_OBJECT(nw), "_notify_daemon"))

static const char *description =
    I18N_NOOP("A DBUS notification to TDE interface.");
static const char *message =
    I18N_NOOP("First release October 2011.");
static const char *version = "0.01";

typedef struct
{
	GTimeVal expiration;
	GTimeVal paused_diff;
	gboolean has_timeout;
	gboolean paused;
	guint id;
	GtkWindow *nw;

} NotifyTimeout;

static DBusConnection *dbus_conn = NULL;

#define CHECK_DBUS_VERSION(major, minor) \
	(DBUS_MAJOR_VER > (major) || \
	 (DBUS_MAJOR_VER == (major) && DBUS_MINOR_VER >= (minor)))

#if !CHECK_DBUS_VERSION(0, 60)
/* This is a hack that will go away in time. For now, it's fairly safe. */
struct _DBusGMethodInvocation
{
	DBusGConnection *connection;
	DBusGMessage *message;
	const DBusGObjectInfo *object;
	const DBusGMethodInfo *method;
};
#endif /* D-BUS < 0.60 */

G_DEFINE_TYPE(NotifyDaemon, notify_daemon, G_TYPE_OBJECT);

static void
notify_daemon_finalize(GObject *object)
{
	NotifyDaemon *daemon       = NOTIFY_DAEMON(object);
	GObjectClass *parent_class = G_OBJECT_CLASS(notify_daemon_parent_class);

	if (parent_class->finalize != NULL)
		parent_class->finalize(object);
}

static void
notify_daemon_class_init(NotifyDaemonClass *daemon_class)
{
	GObjectClass *object_class = G_OBJECT_CLASS(daemon_class);

	object_class->finalize = notify_daemon_finalize;
}

static void
notify_daemon_init(NotifyDaemon *daemon)
{
}

gboolean
notify_daemon_notify_handler(NotifyDaemon *daemon,
							 const gchar *app_name,
							 guint id,
							 const gchar *icon,
							 const gchar *summary,
							 const gchar *body,
							 gchar **actions,
							 GHashTable *hints,
							 int timeout, DBusGMethodInvocation *context)
{
	NotifyDaemonPrivate *priv = daemon->priv;
	NotifyTimeout *nt = NULL;
	GtkWindow *nw = NULL;
	GValue *data;
	gboolean use_pos_data = FALSE;
	gboolean new_notification = FALSE;
	gint x = 0;
	gint y = 0;
	guint return_id;
	gchar *sender;
	gint i;

	/* deal with x, and y hints */
	if ((data = (GValue *)g_hash_table_lookup(hints, "x")) != NULL)
	{
		x = g_value_get_int(data);

		if ((data = (GValue *)g_hash_table_lookup(hints, "y")) != NULL)
		{
			y = g_value_get_int(data);
			use_pos_data = TRUE;
		}
	}

	// Send a notification request to KDE here...
	TQString messageCaption = TQString::fromLocal8Bit(summary);
	TQString messageText = TQString::fromLocal8Bit(body);

	GTKNotifierContainer->displayMessage(messageCaption, messageText, TQString(icon), x, y);
	GTKNotifierContainer->processEvents();

	return_id = 0;

	dbus_g_method_return(context, return_id);

	return TRUE;
}

gboolean
notify_daemon_close_notification_handler(NotifyDaemon *daemon,
										 guint id, GError **error)
{
	// Do nothing

	return TRUE;
}

gboolean
notify_daemon_get_capabilities(NotifyDaemon *daemon, char ***caps)
{
	*caps = g_new0(char *, 6);

	(*caps)[0] = g_strdup("actions");
	(*caps)[1] = g_strdup("body");
	(*caps)[2] = g_strdup("body-hyperlinks");
	(*caps)[3] = g_strdup("body-markup");
	(*caps)[4] = g_strdup("icon-static");
	(*caps)[5] = NULL;

	return TRUE;
}

gboolean
notify_daemon_reload_settings (NotifyDaemon *daemon)
{
	// Do nothing

	return TRUE;
}

gboolean
notify_daemon_get_server_information(NotifyDaemon *daemon,
									 char **out_name,
									 char **out_vendor,
									 char **out_version,
									 char **out_spec_ver)
{
	*out_name     = g_strdup("Notification Daemon");
	*out_vendor   = g_strdup("Trinity Desktop Project");
	*out_version  = g_strdup(VERSION);
	*out_spec_ver = g_strdup("0.1");

	return TRUE;
}

int
main(int argc, char **argv)
{
	NotifyDaemon *daemon;
	DBusGConnection *connection;
	DBusGProxy *bus_proxy;
	GError *error;
	guint request_name_result;
	
	g_set_application_name ("notification-daemon-tde");

#ifdef G_ENABLE_DEBUG
	g_log_set_always_fatal(G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
#endif

	gtk_init(&argc, &argv);

	error = NULL;

	connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);

	if (connection == NULL)
	{
		g_printerr("Failed to open connection to bus: %s\n",
				   error->message);
		g_error_free(error);
		exit(1);
	}

	dbus_conn = dbus_g_connection_get_connection(connection);

	dbus_g_object_type_install_info(NOTIFY_TYPE_DAEMON,
									&dbus_glib_notification_daemon_tde_object_info);

	bus_proxy = dbus_g_proxy_new_for_name(connection,
										  "org.freedesktop.DBus",
										  "/org/freedesktop/DBus",
										  "org.freedesktop.DBus");

	if (!dbus_g_proxy_call(bus_proxy, "RequestName", &error,
						   G_TYPE_STRING, "org.freedesktop.Notifications",
						   G_TYPE_UINT, 0,
						   G_TYPE_INVALID,
						   G_TYPE_UINT, &request_name_result,
						   G_TYPE_INVALID))
	{
		g_error("Could not acquire name: %s", error->message);
	}

	daemon = static_cast<NotifyDaemon*>(g_object_new(NOTIFY_TYPE_DAEMON, NULL));

	dbus_g_connection_register_g_object(connection,
										"/org/freedesktop/Notifications",
										G_OBJECT(daemon));

	TDEAboutData aboutData("notification-daemon-tde", I18N_NOOP("TDE DBUS Notification Daemon"), version,
		description, TDEAboutData::License_GPL,
		"(c) 2011, Timothy Pearson",
		message, 0 /* TODO: Website */, "kb9vqf@pearsoncomputing.net");

	TDECmdLineArgs::init(argc, argv, &aboutData);

	TDEApplication app;
	NotificationContainer nc;
	app.setMainWidget(&nc);
	GTKNotifierContainer = &nc;
	TQTimer *gtkEventProcessor = new TQTimer( &app );
	TQObject::connect( gtkEventProcessor, TQ_SIGNAL(timeout()), &nc, TQ_SLOT(handleGTKMain()) );
	gtkEventProcessor->start( 100, false ); // Every 0.1 seconds poll gtk for DBUS events
	app.disableSessionManagement();
	app.exec();

	return 0;
}

void real_handleGTKMain() {
	while (gtk_events_pending())
		gtk_main_iteration();
}

#include "daemon.moc"
