/*
 * e-mail-formatter-audio-inline.c
 *
 * This program 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 of the License, or (at your option) version 3.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with the program; if not, see <http://www.gnu.org/licenses/>
 *
 */

#include "e-mail-formatter-audio-inline.h"

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <glib/gi18n-lib.h>

#include <libebackend/libebackend.h>

#include <em-format/e-mail-formatter-extension.h>
#include <em-format/e-mail-formatter.h>

#include "e-util/e-mktemp.h"

#include <camel/camel.h>
#include <gst/gst.h>

#include "e-mail-part-audio-inline.h"

#define d(x)

typedef struct _EMailFormatterAudioInline {
	EExtension parent;
} EMailFormatterAudioInline;

typedef struct _EMailFormatterAudioInlineClass {
	EExtensionClass parent_class;
} EMailFormatterAudioInlineClass;

GType e_mail_formatter_audio_inline_get_type (void);
static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);

G_DEFINE_DYNAMIC_TYPE_EXTENDED (
	EMailFormatterAudioInline,
	e_mail_formatter_audio_inline,
	E_TYPE_EXTENSION,
	0,
	G_IMPLEMENT_INTERFACE_DYNAMIC (
		E_TYPE_MAIL_EXTENSION,
		e_mail_formatter_mail_extension_interface_init)
	G_IMPLEMENT_INTERFACE_DYNAMIC (
		E_TYPE_MAIL_FORMATTER_EXTENSION,
		e_mail_formatter_formatter_extension_interface_init));

static const gchar* formatter_mime_types[] = { "application/vnd.evolution.widget.audio-inline",
					       "audio/ac3", "audio/x-ac3",
					       "audio/basic", "audio/mpeg",
					       "audio/x-mpeg", "audio/mpeg3",
					       "audio/x-mpeg3", "audio/mp3",
					       "audio/x-mp3", "audio/mp4",
					       "audio/flac", "audio/x-flac",
					       "audio/mod", "audio/x-mod",
					       "audio/x-wav", "audio/microsoft-wav",
					       "audio/x-wma", "audio/x-ms-wma",
					       "application/ogg", "application/x-ogg",
					       NULL };

static void
pause_clicked (GtkWidget *button,
               EMailPartAudioInline *part)
{
	if (part->playbin) {
		/* pause playing */
		gst_element_set_state (part->playbin, GST_STATE_PAUSED);
	}
}

static void
stop_clicked (GtkWidget *button,
              EMailPartAudioInline *part)
{
	if (part->playbin) {
		/* ready to play */
		gst_element_set_state (part->playbin, GST_STATE_READY);
		part->target_state = GST_STATE_READY;
	}
}

static void
set_audiosink (GstElement *playbin)
{
	GstElement *audiosink;

	/* now it's time to get the audio sink */
	audiosink = gst_element_factory_make ("gconfaudiosink", "play_audio");
	if (audiosink == NULL) {
		audiosink = gst_element_factory_make ("autoaudiosink", "play_audio");
	}

	if (audiosink) {
		g_object_set (playbin, "audio-sink", audiosink, NULL);
	}
}

static gboolean
gst_callback (GstBus *bus,
              GstMessage *message,
              gpointer data)
{
	EMailPartAudioInline *part = data;
	GstMessageType msg_type;

	g_return_val_if_fail (part != NULL, TRUE);
	g_return_val_if_fail (part->playbin != NULL, TRUE);

	msg_type = GST_MESSAGE_TYPE (message);

	switch (msg_type) {
		case GST_MESSAGE_ERROR:
			gst_element_set_state (part->playbin, GST_STATE_NULL);
			break;
		case GST_MESSAGE_EOS:
			gst_element_set_state (part->playbin, GST_STATE_READY);
			break;
		case GST_MESSAGE_STATE_CHANGED:
			{
			      GstState old_state, new_state;

			      if (GST_MESSAGE_SRC (message) != GST_OBJECT (part->playbin))
				      break;

			      gst_message_parse_state_changed (message, &old_state, &new_state, NULL);

			      if (old_state == new_state)
				      break;

			      if (part->play_button)
					gtk_widget_set_sensitive (
						part->play_button,
						new_state <= GST_STATE_PAUSED);
			      if (part->pause_button)
					gtk_widget_set_sensitive (
						part->pause_button,
						new_state > GST_STATE_PAUSED);
			      if (part->stop_button)
					gtk_widget_set_sensitive (
						part->stop_button,
						new_state >= GST_STATE_PAUSED);
			}

			break;
		default:
			break;
	}

	return TRUE;
}

static void
play_clicked (GtkWidget *button,
              EMailPartAudioInline *part)
{
	GstState cur_state;

	d(printf ("audio inline formatter: play\n"));

	if (!part->filename) {
		CamelStream *stream;
		CamelDataWrapper *data;
		GError *error = NULL;
		gint argc = 1;
		const gchar *argv [] = { "org_gnome_audio_inline", NULL };

		/* FIXME this is ugly, we should stream this directly to gstreamer */
		part->filename = e_mktemp ("org-gnome-audio-inline-file-XXXXXX");

		d(printf ("audio inline formatter: write to temp file %s\n", po->filename));

		stream = camel_stream_fs_new_with_name (
			part->filename, O_RDWR | O_CREAT | O_TRUNC, 0600, NULL);
		data = camel_medium_get_content (CAMEL_MEDIUM (part->parent.part));
		camel_data_wrapper_decode_to_stream_sync (data, stream, NULL, NULL);
		camel_stream_flush (stream, NULL, NULL);
		g_object_unref (stream);

		d(printf ("audio inline formatter: init gst playbin\n"));

		if (gst_init_check (&argc, (gchar ***) &argv, &error)) {
			gchar *uri;
			GstBus *bus;

			/* create a disk reader */
			part->playbin = gst_element_factory_make ("playbin", "playbin");
			if (part->playbin == NULL) {
				g_printerr ("Failed to create gst_element_factory playbin; check your installation\n");
				return;

			}

			uri = g_filename_to_uri (part->filename, NULL, NULL);
			g_object_set (part->playbin, "uri", uri, NULL);
			g_free (uri);
			set_audiosink (part->playbin);

			bus = gst_element_get_bus (part->playbin);
			part->bus_id = gst_bus_add_watch (bus, gst_callback, part);
			gst_object_unref (bus);

		} else {
			g_printerr ("GStreamer failed to initialize: %s",error ? error->message : "");
			g_error_free (error);
		}
	}

	gst_element_get_state (part->playbin, &cur_state, NULL, 0);

	if (cur_state >= GST_STATE_PAUSED) {
		gst_element_set_state (part->playbin, GST_STATE_READY);
	}

	if (part->playbin) {
		/* start playing */
		gst_element_set_state (part->playbin, GST_STATE_PLAYING);
	}
}

static GtkWidget *
add_button (GtkWidget *box,
            const gchar *stock_icon,
            GCallback cb,
            gpointer data,
            gboolean sensitive)
{
	GtkWidget *button;

	button = gtk_button_new_from_stock (stock_icon);
	gtk_widget_set_sensitive (button, sensitive);
	g_signal_connect (button, "clicked", cb, data);

	gtk_widget_show (button);
	gtk_box_pack_end (GTK_BOX (box), button, TRUE, TRUE, 0);

	return button;
}

static gboolean
emfe_audio_inline_format (EMailFormatterExtension *extension,
                          EMailFormatter *formatter,
                          EMailFormatterContext *context,
                          EMailPart *part,
                          CamelStream *stream,
                          GCancellable *cancellable)
{
	gchar *str;

	str = g_strdup_printf (
		"<object type=\"application/vnd.evolution.widget.audio-inline\" "
			"width=\"100%%\" height=\"auto\" data=\"%s\" id=\"%s\"></object>",
		part->id, part->id);

	camel_stream_write_string (stream, str, cancellable, NULL);

	g_free (str);

	return TRUE;
}

static GtkWidget *
emfe_audio_inline_get_widget (EMailFormatterExtension *extension,
                              EMailPartList *context,
                              EMailPart *part,
                              GHashTable *params)
{
	GtkWidget *box;
	EMailPartAudioInline *ai_part;

	g_return_val_if_fail (E_MAIL_PART_IS (part, EMailPartAudioInline), NULL);
	ai_part = (EMailPartAudioInline *) part;

	/* it is OK to call UI functions here, since we are called from UI thread */
	box = gtk_hbutton_box_new ();
	ai_part->play_button = g_object_ref (
		add_button (box, GTK_STOCK_MEDIA_PLAY,
			    G_CALLBACK (play_clicked), part, TRUE));
	ai_part->pause_button = g_object_ref (
		add_button (box, GTK_STOCK_MEDIA_PAUSE,
			    G_CALLBACK (pause_clicked), part, FALSE));
	ai_part->stop_button = g_object_ref (
		add_button (box, GTK_STOCK_MEDIA_STOP,
			    G_CALLBACK (stop_clicked), part, FALSE));

	gtk_widget_show (box);

	return box;
}

static const gchar *
emfe_audio_inline_get_display_name (EMailFormatterExtension *extension)
{
	return _("Audio Player");
}

static const gchar *
emfe_audio_inline_get_description (EMailFormatterExtension *extension)
{
	return _("Play the attachment in embedded audio player");
}

static const gchar **
emfe_audio_inline_mime_types (EMailExtension *extension)
{
	return formatter_mime_types;
}

static void
e_mail_formatter_audio_inline_constructed (GObject *object)
{
	EExtensible *extensible;
	EMailExtensionRegistry *reg;

	extensible = e_extension_get_extensible (E_EXTENSION (object));
	reg = E_MAIL_EXTENSION_REGISTRY (extensible);

	e_mail_extension_registry_add_extension (reg, E_MAIL_EXTENSION (object));
}

static void
e_mail_formatter_audio_inline_class_init (EMailFormatterAudioInlineClass *class)
{
	GObjectClass *object_class;
	EExtensionClass *extension_class;

	object_class = G_OBJECT_CLASS (class);
	object_class->constructed = e_mail_formatter_audio_inline_constructed;

	extension_class = E_EXTENSION_CLASS (class);
	extension_class->extensible_type = E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY;
}

static void
e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
{
	iface->format = emfe_audio_inline_format;
	iface->get_widget = emfe_audio_inline_get_widget;
	iface->get_display_name = emfe_audio_inline_get_display_name;
	iface->get_description = emfe_audio_inline_get_description;
}

static void
e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
{
	iface->mime_types = emfe_audio_inline_mime_types;
}

static void
e_mail_formatter_audio_inline_init (EMailFormatterAudioInline *formatter)
{

}

void
e_mail_formatter_audio_inline_type_register (GTypeModule *type_module)
{
	e_mail_formatter_audio_inline_register_type (type_module);
}

static void
e_mail_formatter_audio_inline_class_finalize (EMailFormatterAudioInlineClass *class)
{

}
/tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=c0a327a95531335c8a413afed8ce1b78fc5ca54f'>Update to 0.56.0</a></td><td>sunpoet</td><td><span title='2019-09-09 03:31:51 +0800'>2019-09-09</span></td><td>2</td><td><span class='deletions'>-4</span>/<span class='insertions'>+4</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=71900a12bf1d909f435f3a81e6accfe85b750f0d'>Update to 6.11.3</a></td><td>sunpoet</td><td><span title='2019-09-09 03:31:35 +0800'>2019-09-09</span></td><td>3</td><td><span class='deletions'>-5</span>/<span class='insertions'>+4</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=af3e2f6f3966c38b2b4e260f1e8f192b01cf95f1'>www/py-{dj21,dj22}-drf-yasg: Update to 1.16.1</a></td><td>kai</td><td><span title='2019-09-09 02:50:09 +0800'>2019-09-09</span></td><td>4</td><td><span class='deletions'>-10</span>/<span class='insertions'>+12</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=429a0f641c651a55eb0b78d3c499562ab847cb99'>www/py-drf-yasg: Update to 1.16.1</a></td><td>kai</td><td><span title='2019-09-09 02:46:56 +0800'>2019-09-09</span></td><td>2</td><td><span class='deletions'>-5</span>/<span class='insertions'>+6</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=67fffb86a33643ba12c6e5a7525d04f00826b6ef'>www/grafana6: Switch to USES=go:modules, fix build with go1.13</a></td><td>tobik</td><td><span title='2019-09-08 20:08:15 +0800'>2019-09-08</span></td><td>1</td><td><span class='deletions'>-22</span>/<span class='insertions'>+19</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=a49625e17657cdb64a4ce8431271e7e2a91d1877'>- Update to 4.8.0</a></td><td>wen</td><td><span title='2019-09-08 16:46:15 +0800'>2019-09-08</span></td><td>2</td><td><span class='deletions'>-5</span>/<span class='insertions'>+4</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=c1b89c4fd1aed8211437320538450c0532ffda03'>Mark BROKEN</a></td><td>antoine</td><td><span title='2019-09-08 14:14:19 +0800'>2019-09-08</span></td><td>1</td><td><span class='deletions'>-0</span>/<span class='insertions'>+1</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=fee14b49060da5afa265f10e6f604d83af1aa32c'>www/py-azure-common: Update to 1.1.23</a></td><td>dbaio</td><td><span title='2019-09-08 07:07:06 +0800'>2019-09-08</span></td><td>2</td><td><span class='deletions'>-4</span>/<span class='insertions'>+4</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=c787b90472e147d36f505bb6d2ecfe7f9ca7ad50'>Change RUN_DEPENDS from rubygem-jekyll to rubygem-jekyll3</a></td><td>sunpoet</td><td><span title='2019-09-08 06:48:28 +0800'>2019-09-08</span></td><td>1</td><td><span class='deletions'>-7</span>/<span class='insertions'>+8</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=9459ace9a81cb955527dd1a75e29f1e4e0745faf'>Change RUN_DEPENDS from rubygem-kramdown to rubygem-kramdown1</a></td><td>sunpoet</td><td><span title='2019-09-08 06:48:23 +0800'>2019-09-08</span></td><td>1</td><td><span class='deletions'>-1</span>/<span class='insertions'>+2</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=7c48d78ed3d655b5d0405fe086e1da36d2aa6992'>Update to 0.29</a></td><td>sunpoet</td><td><span title='2019-09-08 06:47:33 +0800'>2019-09-08</span></td><td>2</td><td><span class='deletions'>-7</span>/<span class='insertions'>+8</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=df4cdfa4c4ff69cab7781fa824e4c430633a3c47'>Change RUN_DEPENDS from rubygem-jekyll to rubygem-jekyll3</a></td><td>sunpoet</td><td><span title='2019-09-08 06:47:18 +0800'>2019-09-08</span></td><td>1</td><td><span class='deletions'>-3</span>/<span class='insertions'>+5</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=f1fc02fb112ff68c17339ab1e50fcffc15692f85'>Update to 4.0.0</a></td><td>sunpoet</td><td><span title='2019-09-08 06:47:13 +0800'>2019-09-08</span></td><td>3</td><td><span class='deletions'>-28</span>/<span class='insertions'>+19</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=8329e1c18787a68037dca6b79570f170decba5a2'>Update to 2.2.1</a></td><td>sunpoet</td><td><span title='2019-09-08 06:46:42 +0800'>2019-09-08</span></td><td>2</td><td><span class='deletions'>-6</span>/<span class='insertions'>+6</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=89c97b92cef47a1d9b1a1259942620fc5c804559'>Update to 0.4.0</a></td><td>sunpoet</td><td><span title='2019-09-08 06:44:44 +0800'>2019-09-08</span></td><td>2</td><td><span class='deletions'>-4</span>/<span class='insertions'>+4</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=6edf2aa8d513e2a17eb8fed1b72d7c7c3cc25b44'>Cosmetic change</a></td><td>sunpoet</td><td><span title='2019-09-08 06:44:24 +0800'>2019-09-08</span></td><td>1</td><td><span class='deletions'>-2</span>/<span class='insertions'>+3</span></td></tr>
<tr><td class='commitgraph'>* </td><td><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports/commit/www?h=dependabot/npm_and_yarn/devel/electron4/files/eslint-utils-1.4.3&amp;id=7b57d52ecde3a70e1ebacc02a428820880ac574f'>Update to 1.22</a></td><td>sunpoet</td><td><span title='2019-09-08 06:44:18 +0800'>2019-09-08</span>