#include <clutter-gst/clutter-gst.h>
#include <string.h>
#include <stdlib.h>

#define WIDTH 640
#define HEIGTH 480
#define SCALE 2
#define FPS 25
#define VISUALIZATION "goom"

static void
die(char *msg)
{
	g_error(msg);
	exit(EXIT_FAILURE);
}

static gboolean
filter_features (GstPluginFeature * feature, gpointer data)
{
	GstElementFactory *f;

	if (!GST_IS_ELEMENT_FACTORY (feature))
		return FALSE;
	f = GST_ELEMENT_FACTORY (feature);
		if (!g_strrstr (gst_element_factory_get_klass (f), "Visualization"))
	return FALSE;

	return TRUE;
}

static void
add_visualization(ClutterGstVideoTexture *video_texture)
{
	GList *features;
	GList *feature;
	GstElementFactory *tmp;
	GstElementFactory *fac = NULL;
	GstElement *vis_element;
	GstElement *vis_capsfilter;
	GstElement *playbin;
	GstPad *pad;
	GstCaps *caps;

	features = gst_registry_feature_filter(gst_registry_get_default(),
					       filter_features, FALSE, NULL);

	for (feature = features; feature; feature = feature->next) {
		tmp = GST_ELEMENT_FACTORY(feature->data);
		fprintf(stderr, "Found visualization: %s\n", GST_PLUGIN_FEATURE_NAME(tmp));
		if (!strcmp(GST_PLUGIN_FEATURE_NAME(tmp), VISUALIZATION))
			fac = tmp;
	}
	g_list_free(features);

	if (!fac)
		die("Failed to find visualization");
	else
		fprintf(stderr, "Using visualization " VISUALIZATION "\n");

	vis_element = gst_element_factory_create(fac, "vis_element");
	if (!GST_IS_ELEMENT(vis_element))
		die("Failed to create vis");

	vis_capsfilter = gst_element_factory_make("capsfilter", "vis_capsfilter");
	if (!GST_IS_ELEMENT(vis_capsfilter))
		die("Failed to create caps");

	gst_element_link_pads(vis_element, "src", vis_capsfilter, "sink");

	/* Get allowed output caps from visualisation element */
	pad = gst_element_get_pad(vis_element, "src");
	caps = gst_pad_get_allowed_caps(pad);
	gst_object_unref(pad);

	/* Can we fixate ? */
	if (caps && !gst_caps_is_fixed(caps)) {
		guint i;

		caps = gst_caps_make_writable(caps);

		/* Get visualization size */
		for (i = 0; i < gst_caps_get_size (caps); ++i) {
			GstStructure *s = gst_caps_get_structure (caps, i);

			/* Fixate */
			gst_structure_fixate_field_nearest_int(s, "width", WIDTH / SCALE);
			gst_structure_fixate_field_nearest_int(s, "height", HEIGTH / SCALE);
			gst_structure_fixate_field_nearest_fraction(s, "framerate", FPS, 1);
		}

		/* set this */
		g_object_set(vis_capsfilter, "caps", caps, NULL);
	}

	playbin = clutter_gst_video_texture_get_playbin(video_texture);
	g_object_set(playbin, "vis-plugin", vis_element, NULL);
}

int
main (int argc, char *argv[])
{
	ClutterActor *stage;
	ClutterActor *video;
	ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };

	if (argc < 2)
		die("Missing argument");

	clutter_init(&argc, &argv);
	gst_init(&argc, &argv);
	stage = clutter_stage_get_default();
	clutter_stage_set_color(CLUTTER_STAGE(stage), &stage_color); 
	clutter_actor_set_size(stage, WIDTH, HEIGTH);

	video = g_object_new(CLUTTER_GST_TYPE_VIDEO_TEXTURE, "sync-size", FALSE, "tiled", FALSE, NULL);
	if (!video)
		die("Failed to create video texture");

	clutter_media_set_filename(CLUTTER_MEDIA(video), argv[1]);
	clutter_group_add(CLUTTER_GROUP(stage), video);
	clutter_actor_set_size(video, WIDTH, HEIGTH);
	add_visualization(CLUTTER_GST_VIDEO_TEXTURE(video));

	clutter_media_set_volume(CLUTTER_MEDIA(video), 1.0);
	clutter_media_set_playing(CLUTTER_MEDIA(video), TRUE);
	clutter_actor_show_all(stage);
	g_signal_connect(stage, "key-press-event", G_CALLBACK(clutter_main_quit), NULL);
	clutter_main();

	return EXIT_SUCCESS;
}

