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

#define TIMEOUT 100

//#define REUSE

static void
error_cb (GstBus * bus, GstMessage * msg, GMainLoop * loop)
{
  GError *err = NULL;
  gchar *debug;

  gst_message_parse_error (msg, &err, &debug);
  g_printerr ("ERROR: %s: %s\n", err->message, debug);
  g_clear_error (&err);
  g_free (debug);
  g_main_loop_quit (loop);
}

static void
eos_cb (GstBus * bus, GstMessage * msg, GMainLoop * loop)
{
  g_print ("EOS\n");
  g_main_loop_quit (loop);
}

static gboolean
timeout_cb (gpointer user_data)
{
  g_print ("TIMEOUT\n");
  g_main_loop_quit (user_data);

  return FALSE;
}

#ifdef REUSE
static GstElement *playbin = NULL;
#endif

static void
play_file (const gchar * uri)
{
  GstElement *pipeline;
  GstBus *bus;
  GMainLoop *loop;
  gulong timeout_cb_id, error_cb_id, eos_cb_id;

  g_print ("PLAYING: %s\n", uri);

#ifdef REUSE
  pipeline = gst_object_ref (playbin);
#else
  pipeline = gst_element_factory_make ("playbin", NULL);
#endif
  g_object_set (pipeline, "uri", uri, NULL);

  loop = g_main_loop_new (FALSE, FALSE);

  gst_element_set_state (pipeline, GST_STATE_PLAYING);
  bus = gst_element_get_bus (pipeline);
  gst_bus_add_signal_watch (bus);

  error_cb_id = g_signal_connect (bus, "message::error", (GCallback) error_cb,
      loop);
  eos_cb_id = g_signal_connect (bus, "message::eos", (GCallback) eos_cb, loop);

  timeout_cb_id = g_timeout_add (TIMEOUT, timeout_cb, loop);

  g_main_loop_run (loop);

  g_source_remove (timeout_cb_id);
  g_signal_handler_disconnect (bus, error_cb_id);
  g_signal_handler_disconnect (bus, eos_cb_id);

  gst_bus_remove_signal_watch (bus);
  gst_object_unref (bus);
#ifdef REUSE
  gst_element_set_state (pipeline, GST_STATE_READY);
#else
  gst_element_set_state (pipeline, GST_STATE_NULL);
#endif
  gst_object_unref (pipeline);
  g_main_loop_unref (loop);

  g_print ("\n\n");
}

static void
recurse_directory (const gchar *path)
{
  GError *err = NULL;
  GDir *dir;
  const gchar *filename;
  
  dir = g_dir_open (path, 0, &err);
  if (!dir) {
    g_printerr ("Failed to open %s: %s\n", path, err->message);
    g_clear_error (&err);
    return;
  }

  while ((filename = g_dir_read_name (dir))) {
    GStatBuf sbuf;
    gchar *new_path;

    if (strcmp (filename, ".") == 0 ||
        strcmp (filename, "..") == 0)
      continue;

    new_path = g_build_filename (path, filename, NULL);

    if (g_stat (new_path, &sbuf) < 0) {
      g_printerr ("Failed to stat %s: %s\n", new_path, g_strerror (errno));
      g_free (new_path);
      continue;
    }

    if (sbuf.st_mode & S_IFDIR) {
      recurse_directory (new_path);
    } else if (sbuf.st_mode & S_IFREG) {
      gchar *uri;
      
      uri = gst_filename_to_uri (new_path, &err);
      g_assert (uri != NULL);
      play_file (uri);
      g_free (uri);
    }

    g_free (new_path);
  }

  g_dir_close (dir);
}

int
main (int argc, char *argv[])
{
  gst_init (&argc, &argv);

#ifdef REUSE
  playbin = gst_element_factory_make ("playbin", NULL);
#endif

  recurse_directory (argv[1]);

#ifdef REUSE
  gst_element_set_state (playbin, GST_STATE_NULL);
  gst_object_unref (playbin);
#endif

  return 0;
}
