/*
 * libpurple-translate - Autotranslate messages
 * Copyright (C) 2010  Eion Robb
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */
 
#include "../common/pp_internal.h"

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

#include <util.h>
#include <plugin.h>
#include <debug.h>

#define DEST_LANG_SETTING "eionrobb-translate-lang"
#define LOCALE_PREF       "/plugins/core/eionrobb-libpurple-translate/locale"
#define SERVICE_PREF      "/plugins/core/eionrobb-libpurple-translate/service"

#define GOOGLE_TRANSLATE_URL "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&langpair=%s%%7C%s&q=%s"

#define BING_APPID         "0FFF5300CD157A2E748DFCCF6D67F8028E5B578D"
#define BING_DETECT_URL    "http://api.microsofttranslator.com/V2/Ajax.svc/Detect?appId=" BING_APPID "&text=%%22%s%%22"
#define BING_TRANSLATE_URL "http://api.microsofttranslator.com/V2/Ajax.svc/Translate?appId=" BING_APPID "&text=%%22%s%%22&from=%s&to=%s"

/** This is the list of languages we support, populated in plugin_init */
static GList *supported_languages = NULL;

typedef void(* TranslateCallback)(const gchar *original_phrase, const gchar *translated_phrase, const gchar *detected_language, gpointer userdata);
struct _TranslateStore {
	gchar *original_phrase;
	TranslateCallback callback;
	gpointer userdata;
	gchar *detected_language; //optional - needed for Bing
};

/** Converts unicode strings such as \003d into =
  * Code blatantly nicked from the Facebook plugin */
gchar *
convert_unicode(const gchar *input)
{
	gunichar unicode_char;
	gchar unicode_char_str[6];
	gint unicode_char_len;
	gchar *next_pos;
	gchar *input_string;
	gchar *output_string;

	if (input == NULL)
		return NULL;

	next_pos = input_string = g_strdup(input);

	while ((next_pos = strstr(next_pos, "\\u")))
	{
		/* grab the unicode */
		sscanf(next_pos, "\\u%4x", &unicode_char);
		/* turn it to a char* */
		unicode_char_len = g_unichar_to_utf8(unicode_char, unicode_char_str);
		/* shove it back into the string */
		g_memmove(next_pos, unicode_char_str, unicode_char_len);
		/* move all the data after the \u0000 along */
		g_stpcpy(next_pos + unicode_char_len, next_pos + 6);
	}

	output_string = g_strcompress(input_string);
	g_free(input_string);

	return output_string;
}

const gchar *
get_language_name(const gchar *language_key)
{
	GList *l;
	const gchar *language_name = NULL;
	PurpleKeyValuePair *pair = NULL;
	
	for(l = supported_languages; l; l = l->next)
	{
		pair = (PurpleKeyValuePair *) l->data;
		if (g_str_equal(pair->key, language_key))
		{
			language_name = pair->value;
			break;
		}
	}
	
	return language_name;
}

void
google_translate_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message)
{
	struct _TranslateStore *store = user_data;
	const gchar *trans_start = "\"translatedText\":\"";
	const gchar *lang_start = "\"detectedSourceLanguage\":\"";
	gchar *strstart = NULL;
	gchar *translated = NULL;
	gchar *lang = NULL;

	purple_debug_info("translate", "Got response: %s\n", url_text);
	
	strstart = g_strstr_len(url_text, len, trans_start);
	if (strstart)
	{
		strstart = strstart + strlen(trans_start);
		translated = g_strndup(strstart, strchr(strstart, '"') - strstart);
		
		strstart = convert_unicode(translated);
		g_free(translated);
		translated = strstart;
	}
	
	strstart = g_strstr_len(url_text, len, lang_start);
	if (strstart)
	{
		strstart = strstart + strlen(lang_start);
		lang = g_strndup(strstart, strchr(strstart, '"') - strstart);
	}
	
	store->callback(store->original_phrase, translated, lang, store->userdata);
	
	g_free(translated);
	g_free(lang);
	g_free(store->original_phrase);
	g_free(store);
}

void
google_translate(const gchar *plain_phrase, const gchar *from_lang, const gchar *to_lang, TranslateCallback callback, gpointer userdata)
{
	gchar *encoded_phrase;
	gchar *url;
	struct _TranslateStore *store;
	
	encoded_phrase = g_strdup(purple_url_encode(plain_phrase));
	
	if (!from_lang || g_str_equal(from_lang, "auto"))
		from_lang = "";
	
	url = g_strdup_printf(GOOGLE_TRANSLATE_URL, from_lang, to_lang, encoded_phrase);
	
	store = g_new0(struct _TranslateStore, 1);
	store->original_phrase = g_strdup(plain_phrase);
	store->callback = callback;
	store->userdata = userdata;
	
	purple_debug_info("translate", "Fetching %s\n", url);
	
	purple_util_fetch_url_request(url, TRUE, "libpurple", FALSE, NULL, FALSE, google_translate_cb, store);
	
	g_free(encoded_phrase);
	g_free(url);
}

void
bing_translate_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message)
{
	struct _TranslateStore *store = user_data;
	gchar *translated = NULL;
	gchar *temp;

	purple_debug_info("translate", "Got response: %s\n", url_text);
	
	temp = strchr(url_text, '"') + 1; 
	temp = g_strndup(temp, len - (temp - url_text) - 1);
	
	translated = convert_unicode(temp);
	g_free(temp);
	
	store->callback(store->original_phrase, translated, store->detected_language, store->userdata);
	
	g_free(translated);
	g_free(store->detected_language);
	g_free(store->original_phrase);
	g_free(store);
}

void
bing_translate_autodetect_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message)
{
	struct _TranslateStore *store = user_data;
	gchar *from_lang = NULL;
	gchar *to_lang;
	gchar *encoded_phrase;
	gchar *url;
	
	purple_debug_info("translate", "Got response: %s\n", url_text);
	
	if (!url_text || !len || g_strstr_len(url_text, len, "\"\""))
	{
		// Unknown language
		store->callback(store->original_phrase, store->original_phrase, NULL, store->userdata);
		g_free(store->detected_language);
		g_free(store->original_phrase);
		g_free(store);
		
	} else {
	
		from_lang = strchr(url_text, '"') + 1; 
		from_lang = g_strndup(from_lang, len - (from_lang - url_text) - 1);
		
		to_lang = store->detected_language;
		store->detected_language = from_lang;
		
		// Same as bing_translate() but we've already made the _TranslateStore
		encoded_phrase = g_strescape(purple_url_encode(store->original_phrase), NULL);
		url = g_strdup_printf(BING_TRANSLATE_URL, encoded_phrase, from_lang, to_lang);
		purple_debug_info("translate", "Fetching %s\n", url);
		
		purple_util_fetch_url_request(url, TRUE, "libpurple", FALSE, NULL, FALSE, bing_translate_cb, store);
		
		g_free(to_lang);
		g_free(encoded_phrase);
		g_free(url);
	}
}

void
bing_translate(const gchar *plain_phrase, const gchar *from_lang, const gchar *to_lang, TranslateCallback callback, gpointer userdata)
{
	gchar *encoded_phrase;
	gchar *url;
	struct _TranslateStore *store;
	PurpleUtilFetchUrlCallback urlcallback;
	
	encoded_phrase = g_strescape(purple_url_encode(plain_phrase), NULL);
	
	store = g_new0(struct _TranslateStore, 1);
	store->original_phrase = g_strdup(plain_phrase);
	store->callback = callback;
	store->userdata = userdata;
	
	if (!from_lang || !(*from_lang) || g_str_equal(from_lang, "auto"))
	{
		url = g_strdup_printf(BING_DETECT_URL, encoded_phrase);
		store->detected_language = g_strdup(to_lang);
		urlcallback = bing_translate_autodetect_cb;
	} else {
		url = g_strdup_printf(BING_TRANSLATE_URL, encoded_phrase, from_lang, to_lang);
		urlcallback = bing_translate_cb;
	}
	
	purple_debug_info("translate", "Fetching %s\n", url);
	
	purple_util_fetch_url_request(url, TRUE, "libpurple", FALSE, NULL, FALSE, urlcallback, store);
	
	g_free(encoded_phrase);
	g_free(url);
}

struct TranslateConvMessage {
	PurpleAccount *account;
	gchar *sender;
	PurpleConversation *conv;
	PurpleMessageFlags flags;
};

void
translate_receiving_message_cb(const gchar *original_phrase, const gchar *translated_phrase, const gchar *detected_language, gpointer userdata)
{
	struct TranslateConvMessage *convmsg = userdata;
	PurpleBuddy *buddy;
	gchar *html_text;
	const gchar *language_name = NULL;
	gchar *message;
	
	if (detected_language)
	{
		buddy = purple_find_buddy(convmsg->account, convmsg->sender);
		purple_blist_node_set_string((PurpleBlistNode *)buddy, DEST_LANG_SETTING, detected_language);
		
		language_name = get_language_name(detected_language);
		
		if (language_name != NULL)
		{
			message = g_strdup_printf("Now translating to %s (auto-detected)", language_name);
			purple_conversation_write(convmsg->conv, NULL, message, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
			g_free(message);
		}
	}
	
	html_text = purple_strdup_withhtml(translated_phrase);
	
	purple_conversation_write(convmsg->conv, convmsg->sender, html_text, convmsg->flags, time(NULL));
	
	g_free(html_text);
	g_free(convmsg->sender);
	g_free(convmsg);
}

gboolean
translate_receiving_im_msg(PurpleAccount *account, char **sender,
                             char **message, PurpleConversation *conv,
                             PurpleMessageFlags *flags)
{
	struct TranslateConvMessage *convmsg;
	const gchar *stored_lang = "auto";
	gchar *stripped;
	const gchar *to_lang;
	PurpleBuddy *buddy;
	const gchar *service_to_use = "";
	
	buddy = purple_find_buddy(account, *sender);
	service_to_use = purple_prefs_get_string(SERVICE_PREF);
	to_lang = purple_prefs_get_string(LOCALE_PREF);
	if (buddy)
		stored_lang = purple_blist_node_get_string((PurpleBlistNode *)buddy, DEST_LANG_SETTING);
	if (!stored_lang)
		stored_lang = "auto";
	if (!buddy || !service_to_use || g_str_equal(stored_lang, "none") || g_str_equal(stored_lang, to_lang))
	{
		//Allow the message to go through as per normal
		return FALSE;
	}
	
	if (conv == NULL)
		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, *sender);
	
	stripped = purple_markup_strip_html(*message);
	
	convmsg = g_new0(struct TranslateConvMessage, 1);
	convmsg->account = account;
	convmsg->sender = *sender;
	convmsg->conv = conv;
	convmsg->flags = *flags;
	
	if (g_str_equal(service_to_use, "google"))
	{
		google_translate(stripped, stored_lang, to_lang, translate_receiving_message_cb, convmsg);
	} else if (g_str_equal(service_to_use, "bing"))
	{
		bing_translate(stripped, stored_lang, to_lang, translate_receiving_message_cb, convmsg);
	}
	
	g_free(stripped);
	
	g_free(*message);
	*message = NULL;
	*sender = NULL;
	
	//Cancel the message
	return TRUE;
}


void
translate_receiving_chat_msg_cb(const gchar *original_phrase, const gchar *translated_phrase, const gchar *detected_language, gpointer userdata)
{
	struct TranslateConvMessage *convmsg = userdata;
	PurpleChat *chat;
	gchar *html_text;
	const gchar *language_name = NULL;
	gchar *message;
	
	if (detected_language)
	{
		chat = purple_blist_find_chat(convmsg->account, convmsg->conv->name);
		purple_blist_node_set_string((PurpleBlistNode *)chat, DEST_LANG_SETTING, detected_language);
		
		language_name = get_language_name(detected_language);
		
		if (language_name != NULL)
		{
			message = g_strdup_printf("Now translating to %s (auto-detected)", language_name);
			purple_conversation_write(convmsg->conv, NULL, message, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
			g_free(message);
		}
	}
	
	html_text = purple_strdup_withhtml(translated_phrase);
	
	purple_conversation_write(convmsg->conv, convmsg->sender, html_text, convmsg->flags, time(NULL));
	
	g_free(html_text);
	g_free(convmsg->sender);
	g_free(convmsg);
}

gboolean
translate_receiving_chat_msg(PurpleAccount *account, char **sender,
                             char **message, PurpleConversation *conv,
                             PurpleMessageFlags *flags)
{
	struct TranslateConvMessage *convmsg;
	const gchar *stored_lang = "auto";
	gchar *stripped;
	const gchar *to_lang;
	PurpleChat *chat;
	const gchar *service_to_use = "";
	
	chat = purple_blist_find_chat(account, conv->name);
	service_to_use = purple_prefs_get_string(SERVICE_PREF);
	to_lang = purple_prefs_get_string(LOCALE_PREF);
	if (chat)
		stored_lang = purple_blist_node_get_string((PurpleBlistNode *)chat, DEST_LANG_SETTING);
	if (!stored_lang)
		stored_lang = "auto";
	if (!chat || !service_to_use || g_str_equal(stored_lang, "none") || g_str_equal(stored_lang, to_lang))
	{
		//Allow the message to go through as per normal
		return FALSE;
	}
	
	stripped = purple_markup_strip_html(*message);
	
	convmsg = g_new0(struct TranslateConvMessage, 1);
	convmsg->account = account;
	convmsg->sender = *sender;
	convmsg->conv = conv;
	convmsg->flags = *flags;
	
	if (g_str_equal(service_to_use, "google"))
	{
		google_translate(stripped, stored_lang, to_lang, translate_receiving_chat_msg_cb, convmsg);
	} else if (g_str_equal(service_to_use, "bing"))
	{
		bing_translate(stripped, stored_lang, to_lang, translate_receiving_chat_msg_cb, convmsg);
	}
	
	g_free(stripped);
	
	g_free(*message);
	*message = NULL;
	*sender = NULL;
	
	if (conv == NULL)
	{
		// Fake receiving a message to open the conversation window
		*message = g_strdup(" ");
		*flags |= PURPLE_MESSAGE_INVISIBLE | PURPLE_MESSAGE_NO_LOG;
		return FALSE;
	}
	
	//Cancel the message
	return TRUE;
}

void
translate_sending_message_cb(const gchar *original_phrase, const gchar *translated_phrase, const gchar *detected_language, gpointer userdata)
{
	struct TranslateConvMessage *convmsg = userdata;
	gchar *html_text;
	int err = 0;
	
	html_text = purple_strdup_withhtml(translated_phrase);
	err = serv_send_im(purple_account_get_connection(convmsg->account), convmsg->sender, html_text, convmsg->flags);
	g_free(html_text);
	
	html_text = purple_strdup_withhtml(original_phrase);
	if (err > 0)
	{
		purple_conversation_write(convmsg->conv, convmsg->sender, html_text, convmsg->flags, time(NULL));
	}
	
	purple_signal_emit(purple_conversations_get_handle(), "sent-im-msg",
						convmsg->account, convmsg->sender, html_text);
	
	g_free(html_text);
	g_free(convmsg->sender);
	g_free(convmsg);
}

void
translate_sending_im_msg(PurpleAccount *account, const char *receiver, char **message)
{
	const gchar *from_lang = "";
	const gchar *service_to_use = "";
	const gchar *to_lang = "";
	PurpleBuddy *buddy;
	struct TranslateConvMessage *convmsg;
	gchar *stripped;

	from_lang = purple_prefs_get_string(LOCALE_PREF);
	service_to_use = purple_prefs_get_string(SERVICE_PREF);
	buddy = purple_find_buddy(account, receiver);
	if (buddy)
		to_lang = purple_blist_node_get_string((PurpleBlistNode *)buddy, DEST_LANG_SETTING);
	
	if (!buddy || !service_to_use || !to_lang || g_str_equal(from_lang, to_lang) || g_str_equal(to_lang, "auto"))
	{
		// Don't translate this message
		return;
	}
	
	stripped = purple_markup_strip_html(*message);
	
	convmsg = g_new0(struct TranslateConvMessage, 1);
	convmsg->account = account;
	convmsg->sender = g_strdup(receiver);
	convmsg->conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, receiver, account);
	convmsg->flags = PURPLE_MESSAGE_SEND;
	
	if (g_str_equal(service_to_use, "google"))
	{
		google_translate(stripped, from_lang, to_lang, translate_sending_message_cb, convmsg);
	} else if (g_str_equal(service_to_use, "bing"))
	{
		bing_translate(stripped, from_lang, to_lang, translate_sending_message_cb, convmsg);
	}
	
	g_free(stripped);
	
	g_free(*message);
	*message = NULL;
}

void
translate_sending_chat_message_cb(const gchar *original_phrase, const gchar *translated_phrase, const gchar *detected_language, gpointer userdata)
{
	struct TranslateConvMessage *convmsg = userdata;
	gchar *html_text;
	
	html_text = purple_strdup_withhtml(translated_phrase);
	serv_chat_send(purple_account_get_connection(convmsg->account), purple_conv_chat_get_id(PURPLE_CONV_CHAT(convmsg->conv)), html_text, convmsg->flags);
	g_free(html_text);
	
	html_text = purple_strdup_withhtml(original_phrase);

	purple_signal_emit(purple_conversations_get_handle(), "sent-chat-msg",
						convmsg->account, html_text,
						purple_conv_chat_get_id(PURPLE_CONV_CHAT(convmsg->conv)));
	
	g_free(html_text);
	g_free(convmsg->sender);
	g_free(convmsg);
}

void
translate_sending_chat_msg(PurpleAccount *account, char **message, int chat_id)
{
	const gchar *from_lang = "";
	const gchar *service_to_use = "";
	const gchar *to_lang = "";
	PurpleChat *chat = NULL;
	PurpleConversation *conv;
	struct TranslateConvMessage *convmsg;
	gchar *stripped;

	from_lang = purple_prefs_get_string(LOCALE_PREF);
	service_to_use = purple_prefs_get_string(SERVICE_PREF);
	conv = purple_find_chat(purple_account_get_connection(account), chat_id);
	if (conv)
		chat = purple_blist_find_chat(account, conv->name);
	if (chat)
		to_lang = purple_blist_node_get_string((PurpleBlistNode *)chat, DEST_LANG_SETTING);
	
	if (!chat || !service_to_use || !to_lang || g_str_equal(from_lang, to_lang) || g_str_equal(to_lang, "auto"))
	{
		// Don't translate this message
		return;
	}
	
	stripped = purple_markup_strip_html(*message);
	
	convmsg = g_new0(struct TranslateConvMessage, 1);
	convmsg->account = account;
	convmsg->conv = conv;
	convmsg->flags = PURPLE_MESSAGE_SEND;
	
	if (g_str_equal(service_to_use, "google"))
	{
		google_translate(stripped, from_lang, to_lang, translate_sending_chat_message_cb, convmsg);
	} else if (g_str_equal(service_to_use, "bing"))
	{
		bing_translate(stripped, from_lang, to_lang, translate_sending_chat_message_cb, convmsg);
	}
	
	g_free(stripped);
	
	g_free(*message);
	*message = NULL;
}

static void
translate_action_blist_cb(PurpleBlistNode *node, PurpleKeyValuePair *pair)
{
	PurpleConversation *conv = NULL;
	gchar *message;
	PurpleChat *chat;
	PurpleContact *contact;
	PurpleBuddy *buddy;

	if (pair == NULL)
		purple_blist_node_set_string(node, DEST_LANG_SETTING, NULL);
	else
		purple_blist_node_set_string(node, DEST_LANG_SETTING, pair->key);
	
	switch(node->type)
	{
		case PURPLE_BLIST_CHAT_NODE:
			chat = (PurpleChat *) node;
			conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
							purple_chat_get_name(chat),
							chat->account);
			break;
		case PURPLE_BLIST_CONTACT_NODE:
			contact = (PurpleContact *) node;
			node = (PurpleBlistNode *)purple_contact_get_priority_buddy(contact);
			//fallthrough intentional
		case PURPLE_BLIST_BUDDY_NODE:
			buddy = (PurpleBuddy *) node;
			conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
							purple_buddy_get_name(buddy),
							purple_buddy_get_account(buddy));
			break;
			
		default:
			break;
	}
	
	if (conv != NULL && pair != NULL)
	{
		message = g_strdup_printf("Now translating to %s", (const gchar *)pair->value);
		purple_conversation_write(conv, NULL, message, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
		g_free(message);
	}
}

static void
translate_extended_menu(PurpleBlistNode *node, GList **menu, PurpleCallback callback)
{
	const gchar *stored_lang;
	GList *menu_children = NULL;
	PurpleMenuAction *action;
	PurpleKeyValuePair *pair;
	GList *l;
	
	if (!node)
		return;
	
	stored_lang = purple_blist_node_get_string(node, DEST_LANG_SETTING);
	if (!stored_lang)
		stored_lang = "auto";

	action = purple_menu_action_new(_("Auto"), callback, NULL, NULL);
	menu_children = g_list_append(menu_children, action);
	
	// Spacer
	menu_children = g_list_append(menu_children, NULL);
	
	for(l = supported_languages; l; l = l->next)
	{
		pair = (PurpleKeyValuePair *) l->data;
		action = purple_menu_action_new(pair->value, callback, pair, NULL);
		menu_children = g_list_append(menu_children, action);
	}
	
	// Create the menu for the languages
	action = purple_menu_action_new(_("Translate to..."), NULL, NULL, menu_children);
	*menu = g_list_append(*menu, action);
}

static void
translate_blist_extended_menu(PurpleBlistNode *node, GList **menu)
{
	translate_extended_menu(node, menu, (PurpleCallback)translate_action_blist_cb);
}

static void
translate_action_conv_cb(PurpleConversation *conv, PurpleKeyValuePair *pair)
{
	PurpleBlistNode *node = NULL;
	gchar *message;
	
	if (conv->type == PURPLE_CONV_TYPE_IM)
		node = (PurpleBlistNode *) purple_find_buddy(conv->account, conv->name);
	else if (conv->type == PURPLE_CONV_TYPE_CHAT)
		node = (PurpleBlistNode *) purple_blist_find_chat(conv->account, conv->name);
	
	if (node != NULL)
	{
		translate_action_blist_cb(node, pair);
		
		if (pair != NULL)
		{
			message = g_strdup_printf("Now translating to %s", (const gchar *)pair->value);
			purple_conversation_write(conv, NULL, message, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
			g_free(message);
		}
	}
}

static void
translate_conversation_created(PurpleConversation *conv)
{
	PurpleBlistNode *node = NULL;
	gchar *message;
	const gchar *language_key;
	const gchar *language_name;
	
	if (conv->type == PURPLE_CONV_TYPE_IM)
		node = (PurpleBlistNode *) purple_find_buddy(conv->account, conv->name);
	else if (conv->type == PURPLE_CONV_TYPE_CHAT)
		node = (PurpleBlistNode *) purple_blist_find_chat(conv->account, conv->name);
	
	if (node != NULL)
	{
		language_key = purple_blist_node_get_string(node, DEST_LANG_SETTING);
		
		if (language_key != NULL)
		{
			language_name = get_language_name(language_key);
		
			message = g_strdup_printf(_("Now translating to %s"), language_name);
			purple_conversation_write(conv, NULL, message, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
			g_free(message);
		}
	}
}

static void
translate_conv_extended_menu(PurpleConversation *conv, GList **menu)
{
	PurpleBlistNode *node = NULL;
	
	if (conv->type == PURPLE_CONV_TYPE_IM)
		node = (PurpleBlistNode *) purple_find_buddy(conv->account, conv->name);
	else if (conv->type == PURPLE_CONV_TYPE_CHAT)
		node = (PurpleBlistNode *) purple_blist_find_chat(conv->account, conv->name);
	
	if (node != NULL)
		translate_extended_menu(node, menu, (PurpleCallback)translate_action_conv_cb);
}

static PurplePluginPrefFrame *
plugin_config_frame(PurplePlugin *plugin)
{
	PurplePluginPrefFrame *frame;
	PurplePluginPref *ppref;
	GList *l = NULL;
	PurpleKeyValuePair *pair;
	
	frame = purple_plugin_pref_frame_new();
	
	ppref = purple_plugin_pref_new_with_name_and_label(
		LOCALE_PREF,
		_("My language:"));
	purple_plugin_pref_set_type(ppref, PURPLE_PLUGIN_PREF_CHOICE);
	
	for(l = supported_languages; l; l = l->next)
	{
		pair = (PurpleKeyValuePair *) l->data;
		purple_plugin_pref_add_choice(ppref, pair->value, pair->key);
	}
	
	purple_plugin_pref_frame_add(frame, ppref);
	
	
	ppref = purple_plugin_pref_new_with_name_and_label(
		SERVICE_PREF,
		_("Use service:"));
	purple_plugin_pref_set_type(ppref, PURPLE_PLUGIN_PREF_CHOICE);
	
	purple_plugin_pref_add_choice(ppref, _("Google Translate"), "google");
	purple_plugin_pref_add_choice(ppref, _("Microsoft Translator"), "bing");
	
	purple_plugin_pref_frame_add(frame, ppref);
	
	return frame;
}

static gboolean
plugin_load(PurplePlugin *plugin)
{
	purple_signal_connect(purple_conversations_get_handle(),
	                      "receiving-im-msg", plugin,
	                      PURPLE_CALLBACK(translate_receiving_im_msg), NULL);
	purple_signal_connect(purple_conversations_get_handle(),
						  "sending-im-msg", plugin,
						  PURPLE_CALLBACK(translate_sending_im_msg), NULL);
	purple_signal_connect(purple_blist_get_handle(),
						  "blist-node-extended-menu", plugin,
						  PURPLE_CALLBACK(translate_blist_extended_menu), NULL);
	purple_signal_connect(purple_conversations_get_handle(),
						  "blist-node-extended-menu", plugin,
						  PURPLE_CALLBACK(translate_conv_extended_menu), NULL);
	purple_signal_connect(purple_conversations_get_handle(),
						  "conversation-created", plugin,
						  PURPLE_CALLBACK(translate_conversation_created), NULL);
	purple_signal_connect(purple_conversations_get_handle(),
	                      "receiving-chat-msg", plugin,
	                      PURPLE_CALLBACK(translate_receiving_chat_msg), NULL);
	purple_signal_connect(purple_conversations_get_handle(),
	                      "sending-chat-msg", plugin,
	                      PURPLE_CALLBACK(translate_sending_chat_msg), NULL);
	return TRUE;
}

static gboolean
plugin_unload(PurplePlugin *plugin)
{
	purple_signal_disconnect(purple_conversations_get_handle(),
	                         "receiving-im-msg", plugin,
	                         PURPLE_CALLBACK(translate_receiving_im_msg));
	purple_signal_disconnect(purple_conversations_get_handle(),
							 "sending-im-msg", plugin,
							 PURPLE_CALLBACK(translate_sending_im_msg));
	purple_signal_disconnect(purple_blist_get_handle(),
							 "blist-node-extended-menu", plugin,
							 PURPLE_CALLBACK(translate_blist_extended_menu));
	purple_signal_disconnect(purple_conversations_get_handle(),
							 "blist-node-extended-menu", plugin,
							 PURPLE_CALLBACK(translate_conv_extended_menu));
	purple_signal_disconnect(purple_conversations_get_handle(),
							 "conversation-created", plugin,
							 PURPLE_CALLBACK(translate_conversation_created));
	purple_signal_disconnect(purple_conversations_get_handle(),
	                         "receiving-chat-msg", plugin,
	                         PURPLE_CALLBACK(translate_receiving_chat_msg));
	purple_signal_disconnect(purple_conversations_get_handle(),
	                         "sending-chat-msg", plugin,
	                         PURPLE_CALLBACK(translate_sending_chat_msg));
	return TRUE;
}

static PurplePluginUiInfo prefs_info = {
	plugin_config_frame,
	0,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL
};

static PurplePluginInfo info = {
    PURPLE_PLUGIN_MAGIC,
    2,
    3,
    PURPLE_PLUGIN_STANDARD,
    NULL,
    0,
    NULL,
    PURPLE_PRIORITY_DEFAULT,

    "eionrobb-libpurple-translate",
    NULL,
    PP_VERSION,

    NULL,
    "",
    "Eion Robb <eionrobb@gmail.com>",
    PP_WEBSITE, /* URL */

    plugin_load,   /* load */
    plugin_unload, /* unload */
    NULL,          /* destroy */

    NULL,
    NULL,
    &prefs_info,
    NULL,

	/* reserved */
	NULL,
	NULL,
	NULL,
	NULL
};

static void
init_plugin(PurplePlugin *plugin)
{
	const gchar * const * languages = g_get_language_names();
	const gchar *language;
	guint i = 0;
	PurpleKeyValuePair *pair;

	info.name = _("Auto Translate");
	info.summary = _("Translate incoming/outgoing messages");

	while((language = languages[i++]))
		if (language && strlen(language) == 2)
			break;
	if (!language || strlen(language) != 2)
		language = "en";
	
	purple_prefs_add_none("/plugins/core/eionrobb-libpurple-translate");
	purple_prefs_add_string(LOCALE_PREF, language);
	purple_prefs_add_string(SERVICE_PREF, "google");
	
#define add_language(label, code) \
	pair = g_new0(PurpleKeyValuePair, 1); \
	pair->key = g_strdup(code); \
	pair->value = g_strdup(label); \
	supported_languages = g_list_append(supported_languages, pair);
	
	add_language(_("Afrikaans"), "af");
	add_language(_("Albanian"), "sq");
	add_language(_("Arabic"), "ar");
	add_language(_("Armenian"), "hy");
	add_language(_("Azerbaijani"), "az");
	add_language(_("Basque"), "eu");
	add_language(_("Belarusian"), "be");
	add_language(_("Bulgarian"), "bg");
	add_language(_("Catalan"), "ca");
	add_language(_("Chinese (Simplified)"), "zh-CN");
	add_language(_("Chinese (Traditional)"), "zh-TW");
	add_language(_("Croatian"), "hr");
	add_language(_("Czech"), "cs");
	add_language(_("Danish"), "da");
	add_language(_("Dutch"), "nl");
	add_language(_("English"), "en");
	add_language(_("Estonian"), "et");
	add_language(_("Filipino"), "tl");
	add_language(_("Finnish"), "fi");
	add_language(_("French"), "fr");
	add_language(_("Galician"), "gl");
	add_language(_("Georgian"), "ka");
	add_language(_("German"), "de");
	add_language(_("Greek"), "el");
	add_language(_("Haitian Creole"), "ht");
	add_language(_("Hebrew"), "iw");
	add_language(_("Hindi"), "hi");
	add_language(_("Hungarian"), "hu");
	add_language(_("Icelandic"), "is");
	add_language(_("Indonesian"), "id");
	add_language(_("Irish"), "ga");
	add_language(_("Italian"), "it");
	add_language(_("Japanese"), "ja");
	add_language(_("Korean"), "ko");
	add_language(_("Latin"), "la");
	add_language(_("Latvian"), "lv");
	add_language(_("Lithuanian"), "lt");
	add_language(_("Macedonian"), "mk");
	add_language(_("Malay"), "ms");
	add_language(_("Maltese"), "mt");
	add_language(_("Norwegian"), "no");
	add_language(_("Persian"), "fa");
	add_language(_("Polish"), "pl");
	add_language(_("Portuguese"), "pt");
	add_language(_("Romanian"), "ro");
	add_language(_("Russian"), "ru");
	add_language(_("Serbian"), "sr");
	add_language(_("Slovak"), "sk");
	add_language(_("Slovenian"), "sl");
	add_language(_("Spanish"), "es");
	add_language(_("Swahili"), "sw");
	add_language(_("Swedish"), "sv");
	add_language(_("Thai"), "th");
	add_language(_("Turkish"), "tr");
	add_language(_("Ukrainian"), "uk");
	add_language(_("Urdu"), "ur");
	add_language(_("Vietnamese"), "vi");
	add_language(_("Welsh"), "cy");
	add_language(_("Yiddish"), "yi");
}

PURPLE_INIT_PLUGIN(translate, init_plugin, info);
