/*
 * pidgin-vibr - Indicate events by vibrating.
 * Copyright (C) 2009 Joshua Judson Rosen <rozzin@geekspace.com>;
 * based on pidgin-libnotify 0.13, copyright (C) 2005-2007 Duarte Henriques.
 *
 * 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
 * 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 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 "gln_intl.h"

#ifndef PURPLE_PLUGINS
#define PURPLE_PLUGINS
#endif

#include <glib.h>

#include <version.h>
#include <debug.h>
#include <util.h>
#include <privacy.h>

#include <string.h>

#define PLUGIN_ID "pidgin-vibr"

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

static DBusGConnection *dbus_cxn = NULL;
static DBusGProxy *dbus_prx = NULL;

static PurplePluginPrefFrame *
get_plugin_pref_frame (PurplePlugin *plugin)
{
	PurplePluginPrefFrame *frame;
	PurplePluginPref *ppref;

	frame = purple_plugin_pref_frame_new ();

	ppref = purple_plugin_pref_new_with_name_and_label (
                            "/plugins/vibr/newmsg",
                            _("New messages"));
	purple_plugin_pref_frame_add (frame, ppref);

	ppref = purple_plugin_pref_new_with_name_and_label (
                            "/plugins/vibr/newconvonly",
                            _("Only new conversations"));
	purple_plugin_pref_frame_add (frame, ppref);

	ppref = purple_plugin_pref_new_with_name_and_label (
                            "/plugins/vibr/blocked",
                            _("Ignore events from blocked users"));
	purple_plugin_pref_frame_add (frame, ppref);

	ppref = purple_plugin_pref_new_with_name_and_label (
                            "/plugins/vibr/signon",
                            _("Buddy signs on"));
	purple_plugin_pref_frame_add (frame, ppref);

	ppref = purple_plugin_pref_new_with_name_and_label (
                            "/plugins/vibr/signoff",
                            _("Buddy signs off"));
	purple_plugin_pref_frame_add (frame, ppref);

	return frame;
}

/* Signon flood be gone! - thanks to the guifications devs */
static GList *just_signed_on_accounts = NULL;

static gboolean
event_connection_throttle_cb (gpointer data)
{
	PurpleAccount *account;

	account = (PurpleAccount *)data;

	if (!account)
		return FALSE;

	if (!purple_account_get_connection (account)) {
		just_signed_on_accounts = g_list_remove (just_signed_on_accounts, account);
		return FALSE;
	}

	if (!purple_account_is_connected (account))
		return TRUE;

	just_signed_on_accounts = g_list_remove (just_signed_on_accounts, account);
	return FALSE;
}

static void
event_connection_throttle (PurpleConnection *conn, gpointer data)
{
	PurpleAccount *account;

	/* TODO: this function gets called after buddy signs on for GTalk
	   users who have themselves as a buddy */
	purple_debug_info (PLUGIN_ID, "event_connection_throttle() called\n");

	if (!conn)
		return;

	account = purple_connection_get_account(conn);
	if (!account)
		return;

	just_signed_on_accounts = g_list_prepend (just_signed_on_accounts, account);
	g_timeout_add (5000, event_connection_throttle_cb, (gpointer)account);
}

static gboolean
should_vibr_unavailable (PurpleAccount *account)
{
	PurpleStatus *status;

	if (!purple_prefs_get_bool ("/plugins/vibr/only_available"))
		return TRUE;

	status = purple_account_get_active_status (account);

	return purple_status_is_online (status) && purple_status_is_available (status);
}

static void
notify ()
{
	printf ("BUZZ....\n");
	dbus_g_proxy_call_no_reply (dbus_prx, "SetBrightness",
		G_TYPE_INT, 255, G_TYPE_INVALID,
		G_TYPE_INVALID);
        usleep (.25e6);
	dbus_g_proxy_call_no_reply (dbus_prx, "SetBrightness",
		G_TYPE_INT, 0, G_TYPE_INVALID,
		G_TYPE_INVALID);
}

static void
vibr_buddy_signon_cb (PurpleBuddy *buddy,
						gpointer data)
{
	gboolean blocked;

	g_return_if_fail (buddy);

	if (!purple_prefs_get_bool ("/plugins/vibr/signon"))
		return;

	if (g_list_find (just_signed_on_accounts, buddy->account))
		return;

	blocked = purple_prefs_get_bool ("/plugins/vibr/blocked");
	if (!purple_privacy_check (buddy->account, buddy->name) && blocked)
		return;

	if (!should_vibr_unavailable (purple_buddy_get_account (buddy)))
		return;

	notify ();
}

static void
vibr_buddy_signoff_cb (PurpleBuddy *buddy, gpointer data)
{
	gboolean blocked;

	g_return_if_fail (buddy);

	if (!purple_prefs_get_bool ("/plugins/vibr/signoff"))
		return;

	if (g_list_find (just_signed_on_accounts, buddy->account))
		return;

	blocked = purple_prefs_get_bool ("/plugins/vibr/blocked");
	if (!purple_privacy_check (buddy->account, buddy->name) && blocked)
		return;

	if (!should_vibr_unavailable (purple_buddy_get_account (buddy)))
		return;

	notify ();
}

static void
vibr_msg_sent (PurpleAccount *account,
		 const gchar *sender,
		 const gchar *message)
{
	PurpleBuddy *buddy;
	gboolean blocked;

	buddy = purple_find_buddy (account, sender);
	if (!buddy)
		return;

	blocked = purple_prefs_get_bool ("/plugins/vibr/blocked");
	if (!purple_privacy_check(account, sender) && blocked)
		return;

	notify ();
}

static void
vibr_new_message_cb (PurpleAccount *account,
		   const gchar *sender,
		   const gchar *message,
		   int flags,
		   gpointer data)
{
	PurpleConversation *conv;

	if (!purple_prefs_get_bool ("/plugins/vibr/newmsg"))
		return;

	conv = purple_find_conversation_with_account (PURPLE_CONV_TYPE_IM, sender, account);

	if (conv && purple_prefs_get_bool ("/plugins/vibr/newconvonly")) {
		purple_debug_info (PLUGIN_ID, "Conversation is not new 0x%x\n", conv);
		return;
	}

	if (!should_vibr_unavailable (account))
		return;

	vibr_msg_sent (account, sender, message);
}

static void
vibr_chat_nick (PurpleAccount *account,
		  const gchar *sender,
		  const gchar *message,
		  PurpleConversation *conv,
		  gpointer data)
{
	gchar *nick;

	nick = (gchar *)purple_conv_chat_get_nick (PURPLE_CONV_CHAT(conv));
	if (nick && !strcmp (sender, nick))
		return;

	if (!g_strstr_len (message, strlen(message), nick))
		return;

	vibr_msg_sent (account, sender, message);
}

static gboolean
plugin_load (PurplePlugin *plugin)
{
	void *conv_handle, *blist_handle, *conn_handle;

	conv_handle = purple_conversations_get_handle ();
	blist_handle = purple_blist_get_handle ();
	conn_handle = purple_connections_get_handle();

	purple_signal_connect (blist_handle, "buddy-signed-on", plugin,
						PURPLE_CALLBACK(vibr_buddy_signon_cb), NULL);

	purple_signal_connect (blist_handle, "buddy-signed-off", plugin,
						PURPLE_CALLBACK(vibr_buddy_signoff_cb), NULL);

	purple_signal_connect (conv_handle, "received-im-msg", plugin,
						PURPLE_CALLBACK(vibr_new_message_cb), NULL);

	purple_signal_connect (conv_handle, "received-chat-msg", plugin,
						PURPLE_CALLBACK(vibr_chat_nick), NULL);

	/* used just to avoid the flood of notifications we'd get */
	purple_signal_connect (conn_handle, "signed-on", plugin,
						PURPLE_CALLBACK(event_connection_throttle), NULL);

	return TRUE;
}

static gboolean
plugin_unload (PurplePlugin *plugin)
{
	void *conv_handle, *blist_handle, *conn_handle;

	conv_handle = purple_conversations_get_handle ();
	blist_handle = purple_blist_get_handle ();
	conn_handle = purple_connections_get_handle();

	purple_signal_disconnect (blist_handle, "buddy-signed-on", plugin,
							PURPLE_CALLBACK(vibr_buddy_signon_cb));

	purple_signal_disconnect (blist_handle, "buddy-signed-off", plugin,
							PURPLE_CALLBACK(vibr_buddy_signoff_cb));

	purple_signal_disconnect (conv_handle, "received-im-msg", plugin,
							PURPLE_CALLBACK(vibr_new_message_cb));

	purple_signal_disconnect (conv_handle, "received-chat-msg", plugin,
							PURPLE_CALLBACK(vibr_chat_nick));

	purple_signal_disconnect (conn_handle, "signed-on", plugin,
							PURPLE_CALLBACK(event_connection_throttle));

	return TRUE;
}

static PurplePluginUiInfo prefs_info = {
    get_plugin_pref_frame,
    0,						/* page num (Reserved) */
    NULL					/* frame (Reserved) */
};

static PurplePluginInfo info = {
    PURPLE_PLUGIN_MAGIC,	/* api version */
    PURPLE_MAJOR_VERSION,
    PURPLE_MINOR_VERSION,
    PURPLE_PLUGIN_STANDARD,	/* type */
    0,				/* ui requirement */
    0,				/* flags */
    NULL,			/* dependencies */
    PURPLE_PRIORITY_DEFAULT,	/* priority */

    PLUGIN_ID,			/* id */
    NULL,			/* name */
    VERSION,			/* version */
    NULL,			/* summary */
    NULL,			/* description */

    "Joshua Judson Rosen <rozzin@geekspace.com>",	/* author */
    "http://www.rozzin.com/pidgin-vibr/",		/* homepage */

    plugin_load,			/* load */
    plugin_unload,			/* unload */
    NULL,					/* destroy */
    NULL,					/* ui info */
    NULL,					/* extra info */
    &prefs_info				/* prefs info */
};

static void
init_plugin (PurplePlugin *plugin)
{
	GError *error = NULL;

	bindtextdomain (PACKAGE, LOCALEDIR);
	bind_textdomain_codeset (PACKAGE, "UTF-8");

	info.name = _("Vibration");
	info.summary = _("Indicate events by vibrating.");
	info.description = _("Pidgin-vibr:\nIndicate events by vibrating.");

	purple_prefs_add_none ("/plugins/vibr");
	purple_prefs_add_bool ("/plugins/vibr/newmsg", TRUE);
	purple_prefs_add_bool ("/plugins/vibr/blocked", TRUE);
	purple_prefs_add_bool ("/plugins/vibr/newconvonly", FALSE);
	purple_prefs_add_bool ("/plugins/vibr/signon", TRUE);
	purple_prefs_add_bool ("/plugins/vibr/signoff", FALSE);
	purple_prefs_add_bool ("/plugins/vibr/only_available", FALSE);

	dbus_cxn = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);

	dbus_prx = dbus_g_proxy_new_for_name (dbus_cxn,
		"org.freesmartphone.odeviced",
		"/org/freesmartphone/Device/LED/neo1973_vibrator",
		"org.freesmartphone.Device.LED");
	printf ("Setup DBUS for vibrator: %p %p\n", dbus_cxn, dbus_prx);
}

PURPLE_INIT_PLUGIN(notify, init_plugin, info)

