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

/**
 *
 *
 *
 */

static void
gst_element_sync_children_states_foreach (const GValue *value, gpointer user_data)
{
	gboolean *success = user_data;
	GstElement *element = g_value_get_object (value);

	*success = *success && gst_element_sync_state_with_parent (element);
}

static gboolean
gst_element_sync_children_states (GstBin *bin)
{
	GstIterator *it = gst_bin_iterate_elements (bin);
	GstIteratorResult res = GST_ITERATOR_OK;
	gboolean success = TRUE;

	do {
		if (res == GST_ITERATOR_RESYNC) {
			success = TRUE;
			gst_iterator_resync (it);
		}
		res = gst_iterator_foreach (it, gst_element_sync_children_states_foreach, &success);
	} while (res == GST_ITERATOR_RESYNC);
	gst_iterator_free (it);
	return success;
}

static void
pad_added (GstElement * decodebin, GstPad * pad, gpointer user_data)
{
	GstElement *element = user_data;
	GstCaps *caps = gst_pad_get_current_caps (pad);
	GstStructure *struc = gst_caps_get_structure (caps, 0);
	const gchar *type = gst_structure_get_name (struc);
	GstPad *sinkpad = NULL;
	gchar *pad_name;

	pad_name = gst_pad_get_name (pad);
	if (caps == NULL)
          g_print ("Pad %s has no caps\n", pad_name);
	g_free (pad_name);

	if (g_str_has_prefix (type, "video")) {
		GstElement *vq, *sink;
		vq = gst_element_factory_make ("queue", "vq");
		sink = gst_element_factory_make ("autovideosink", "sink");
		gst_bin_add_many (GST_BIN (element), vq, sink, NULL);
		gst_element_link_many (vq, sink, NULL);
		sinkpad = gst_element_get_static_pad (vq, "sink");
	} else if (g_str_has_prefix (type, "audio")) {
		GstElement *aq, *asink;
		aq = gst_element_factory_make ("queue", "aq");
		asink = gst_element_factory_make ("autoaudiosink", "asink");
		gst_bin_add_many (GST_BIN (element), aq, asink, NULL);
		gst_element_link_many (aq, asink, NULL);
		sinkpad = gst_element_get_static_pad (aq, "sink");
	}
	if (sinkpad != NULL) {
		gst_pad_link (pad, sinkpad);
		gst_object_unref (sinkpad);
		gst_element_sync_children_states (GST_BIN (element));
	}
	gst_caps_unref (caps);
	GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (element), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline");
}

int
main (int argc, char **argv)
{
	GstElement *element, *src, *decodebin;
	GstBus *bus;
	GstMessage *msg = NULL;

	gst_init (&argc, &argv);
	src = gst_element_factory_make ("filesrc", "src");
	decodebin = gst_element_factory_make ("decodebin", "decodebin");
	g_object_set (G_OBJECT (src), "location", "bbb_sunflower_480p_30fps_normal.mov", NULL);
	element = gst_pipeline_new ("pipe");
	gst_bin_add_many (GST_BIN (element), src, decodebin, NULL);
	gst_element_link (src, decodebin);
	gst_element_set_state (element, GST_STATE_PLAYING);
	bus = gst_pipeline_get_bus (GST_PIPELINE(element));
	g_signal_connect (G_OBJECT (decodebin), "pad-added", G_CALLBACK (pad_added), element);
	do {
		if (msg != NULL) {
			gst_message_unref (msg);
		}
		msg = gst_bus_timed_pop (bus, GST_CLOCK_TIME_NONE);
		if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
			gst_message_unref (msg);
			gst_element_set_state (element, GST_STATE_NULL);
			gst_object_unref (bus);
			gst_object_unref (element);
			g_print ("noooooo :(\n");
			return 1;
		}
	} while (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_EOS);
	gst_element_set_state (element, GST_STATE_NULL);
	gst_message_unref (msg);
	gst_object_unref (bus);
	gst_object_unref (element);
	return 0;

}
