#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gst/gst.h>

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

static GstStaticPadTemplate subsinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("text/plain; text/x-pango-markup; video/x-dvd-subpicture"));

typedef struct _App App;

struct _App
{
  GstElement *playbin;
  GstElement *appsink;
  GstElement *subtitlebin;
  GstElement *dvdsubdec;

  GMainLoop *loop;
};

App s_app;

static gboolean
bus_message (GstBus * bus, GstMessage * message, App * app)
{
  GST_DEBUG ("got message %s",
      gst_message_type_get_name (GST_MESSAGE_TYPE (message)));

  switch (GST_MESSAGE_TYPE (message)) {
    case GST_MESSAGE_ERROR:
    {
      GError *gerror;
      gchar *debug;

      gst_message_parse_error (message, &gerror, &debug);
      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
      g_error_free (gerror);
      g_free (debug);

      g_main_loop_quit (app->loop);
      break;
    }
    case GST_MESSAGE_WARNING:
    {
      GError *gerror;
      gchar *debug;

      gst_message_parse_warning (message, &gerror, &debug);
      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
      g_error_free (gerror);
      g_free (debug);

      g_main_loop_quit (app->loop);
      break;
    }
    case GST_MESSAGE_EOS:
      g_message ("received EOS");
      g_main_loop_quit (app->loop);
      break;
    default:
    {
	gchar *sourceName;
	GstObject *source;

	source = GST_MESSAGE_SRC(message);
	sourceName = gst_object_get_name(source);
	if (gst_message_get_structure(message))
	{
		gchar *string = gst_structure_to_string(gst_message_get_structure(message));
		g_print("eServiceMP3::gst_message from %s: %s\n", sourceName, string);
		g_free(string);
	}
	else
		g_print("eServiceMP3::gst_message from %s: %s (without structure)\n", sourceName, GST_MESSAGE_TYPE_NAME(message));
      break;
    }
  }
  return TRUE;
}

static void
have_subtitle (GstElement * appsink, App * app)
{
  GstBuffer *buffer;

  /* get the buffer, we can also wakeup the mainloop to get the subtitle from
   * appsink in the mainloop */
  g_signal_emit_by_name (appsink, "pull-buffer", &buffer);

  if (buffer) {
    guint8 *data;
    guint size;
    GstFormat format;
    gint64 position;
    GstClock *clock;
    GstClockTime base_time, running_time;

    format = GST_FORMAT_TIME;
    gst_element_query_position (appsink, &format, &position);

    clock = gst_element_get_clock (appsink);
    base_time = gst_element_get_base_time (appsink);

    running_time = gst_clock_get_time (clock) - base_time;

    gst_object_unref (clock);

    g_message ("received a subtitle at position %" GST_TIME_FORMAT
        ", running_time %" GST_TIME_FORMAT, GST_TIME_ARGS (position),
        GST_TIME_ARGS (running_time));

    data = GST_BUFFER_DATA (buffer);
    size = GST_BUFFER_SIZE (buffer);

    gst_util_dump_mem (data, size);
  }
}

GstCaps* gstGhostpadGetCAPS (GstPad * pad)
{
	g_print("gstGhostpadGetCAPS");
	return gst_static_pad_template_get_caps(&subsinktemplate);
// 	return gst_pad_get_pad_template_caps(pad);
// 	return get_pad_template_caps(pad);
// 	GstCaps* caps = gst_caps_from_string("text/plain; text/x-pango-markup; video/x-dvd-subpicture");
// 	return caps;
}

void gstCBsubtitleCAPS(GObject *obj, GParamSpec *pspec, gpointer user_data)
{
	g_print("gstCBsubtitleCAPS:: signal::caps callback obj=%p\n", obj);
}

int
main (int argc, char *argv[])
{
  App *app = &s_app;
  GstBus *bus;

  gst_init (&argc, &argv);

  if (argc < 2) {
    g_print ("usage: %s <filename>\n", argv[0]);
    return -1;
  }

  /* create a mainloop to get messages */
  app->loop = g_main_loop_new (NULL, TRUE);

  app->playbin = gst_element_factory_make ("playbin2", NULL);
  g_assert (app->playbin);

  /* set appsink to get the subtitles */  
  app->appsink = gst_element_factory_make ("appsink", "subtitle_sink");
  g_object_set (G_OBJECT (app->appsink), "emit-signals", TRUE, NULL);
  g_object_set (G_OBJECT (app->appsink), "ts-offset", 0 * GST_SECOND, NULL);
  g_signal_connect (app->appsink, "new-buffer", G_CALLBACK (have_subtitle), app);

  app->dvdsubdec = gst_element_factory_make("dvdsubdec", "vobsubtitle_decoder");

  app->subtitlebin = gst_bin_new("subtitle_bin");
  
  gst_bin_add_many(GST_BIN(app->subtitlebin), app->appsink, app->dvdsubdec, NULL);
  
		GstPadTemplate *templ;
		templ = gst_static_pad_template_get (&subsinktemplate);
  
		GstPad *ghostpad = gst_ghost_pad_new_no_target_from_template("sink", templ);
		gst_element_add_pad (app->subtitlebin, ghostpad);

		g_signal_connect (ghostpad, "notify::caps", G_CALLBACK (gstCBsubtitleCAPS), app);

		GstCaps* caps = gst_caps_from_string("text/plain; text/x-pango-markup; video/x-raw-rgb");
		g_object_set (G_OBJECT (app->appsink), "caps", caps, NULL);
		gst_caps_unref(caps);
		
		gst_pad_set_getcaps_function (ghostpad, gstGhostpadGetCAPS);

  
  g_object_set (G_OBJECT (app->playbin), "flags", 0x45, NULL);
  g_object_set (G_OBJECT (app->playbin), "text-sink", app->subtitlebin, NULL);
  
  g_object_set (G_OBJECT (app->dvdsubdec), "singlebuffer", TRUE, NULL);

  bus = gst_pipeline_get_bus (GST_PIPELINE (app->playbin));

  /* add watch for messages */
  gst_bus_add_watch (bus, (GstBusFunc) bus_message, app);

  g_object_set (app->playbin, "uri", argv[1], NULL);
  
  if ( argc == 3 )
  {
    g_message ("using external subtitles %s", argv[2]);
    g_object_set (app->playbin, "suburi", argv[2], NULL);
  }

  /* go to playing and wait in a mainloop. */
  gst_element_set_state (app->playbin, GST_STATE_PLAYING);

  /* this mainloop is stopped when we receive an error or EOS */
  g_main_loop_run (app->loop);

  g_message ("stopping");

  gst_element_set_state (app->playbin, GST_STATE_NULL);

  gst_object_unref (bus);
  g_main_loop_unref (app->loop);

  return 0;
}

