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

#define LPCM_CAPS "audio/x-raw-int,channels=2,rate=44100,width=16,depth=16,signed=true,endianness=1234"

static gboolean
on_autoplug_continue (GstElement *element, GstPad *newpad, GstCaps *_caps, gpointer userdata) {
    GstPad *sink;
    GstElement *encoder;
    GstCaps *caps;

    encoder = GST_ELEMENT (userdata);

    sink = gst_element_get_compatible_pad (encoder, newpad, NULL);

    caps = gst_pad_get_caps (newpad);
    g_signal_emit_by_name (G_OBJECT (encoder), "request-pad", caps, &sink, NULL);

    return sink == NULL;
}

static void
on_pad_added (GstElement *element, GstPad *newpad, gpointer userdata) {
    GstPad *sink;
    GstElement *encoder;

    encoder = GST_ELEMENT (userdata);

    sink = gst_element_get_compatible_pad (encoder, newpad, NULL);
    if (!sink) {
        GstCaps *caps;

        caps = gst_pad_get_caps (newpad);
        g_signal_emit_by_name (G_OBJECT (encoder), "request-pad", caps, &sink, NULL);
    }

    if (!sink) {
        g_debug ("No compatible encodebin pad found for '%s', ignoring...",
                 gst_pad_get_name (newpad));

        return;
    }

    if (gst_pad_link (newpad, sink) == GST_PAD_LINK_OK) {
        g_warning ("Could not link pad '%s' to '%s'",
                   gst_pad_get_name (newpad),
                   gst_pad_get_name (sink));
    }
}

static GstElement*
create_transcode_bin () {
    GstElement *encoder, *decoder, *src, *bin;
    GstEncodingAudioProfile *profile;
    GstCaps *caps;
    GstPad *pad, *ghost;

    encoder = gst_element_factory_make ("encodebin", NULL);
    decoder = gst_element_factory_make ("decodebin2", NULL);

    caps = gst_caps_from_string (LPCM_CAPS);
    profile = gst_encoding_audio_profile_new (caps, NULL, NULL, 1);
    g_object_set (encoder, "profile", profile, NULL);

    bin = gst_bin_new ("transcode-src");
    src = gst_element_make_from_uri (GST_URI_SRC, "file:///tmp/test.jpg", NULL);
    gst_bin_add_many (GST_BIN (bin), src, encoder, decoder, NULL);
    gst_element_link (src, decoder);

    g_signal_connect (decoder, "pad-added", G_CALLBACK (on_pad_added), encoder);
    g_signal_connect (decoder, "autoplug-continue", G_CALLBACK (on_autoplug_continue), encoder);

    pad = gst_element_get_static_pad (encoder, "src");
    ghost = gst_ghost_pad_new (NULL, pad);
    gst_element_add_pad (GST_ELEMENT (bin), ghost);


    return bin;
}

gboolean
on_bus_watch (GstBus *bus, GstMessage *msg, gpointer userdata) {
    g_debug ("Message %s from %s",
             GST_MESSAGE_TYPE_NAME (msg),
             (msg->src) ? GST_OBJECT_NAME (msg->src) : "unknown");

    return TRUE;
}

static gboolean
run (gpointer userdata) {
    gst_element_set_state (GST_ELEMENT (userdata), GST_STATE_PLAYING);

    return FALSE;
}

int
main (int argc, char **argv) {
    GMainLoop *loop;

    GstElement *fakesink, *transcoder, *pipeline;
    GstPad *pad;
    GstBus *bus;

    gst_init (&argc, &argv);

    fakesink = gst_element_factory_make ("udpsink", NULL);
    transcoder = create_transcode_bin ();

    pipeline = gst_pipeline_new ("pipeline");
    gst_bin_add_many (GST_BIN (pipeline),
                      transcoder,
                      fakesink,
                      NULL);
    if (transcoder->numpads == 0) {
        g_debug ("Would need dynamic linking");
//        g_signal_connect (transcoder, "pad-added", on_pad_added, NULL);
    } else {
        gst_element_link (transcoder, fakesink);
    }

    bus = gst_element_get_bus (GST_ELEMENT (pipeline));
    gst_bus_add_watch (bus, on_bus_watch, NULL);

    loop = g_main_loop_new (NULL, FALSE);

    g_idle_add (run, pipeline);

    g_main_loop_run (loop);
}
