/* gcc [ -DNO_RESET_LAYERS ] -o test -Wall -Werror `pkg-config --libs --cflags gst-editing-services-0.10` main.c */
/* ./test ... */

#include <ges/ges.h>

#define DURATION ((gint64) (2 * GST_SECOND))

static gchar *audio_uri = NULL;
static gchar *video_uri = NULL;
static GstElement *pipeline = NULL;
static GstBus *bus = NULL;
gint async_bus_handler_id = 0;
GMainLoop *loop = NULL;

static void
destroy_pipeline()
{
  gst_element_set_state(pipeline, GST_STATE_NULL);
  g_source_remove(async_bus_handler_id);
  gst_object_unref(bus);
  gst_object_unref(pipeline);
}

static gboolean
async_bus_handler(GstBus *bus, GstMessage *msg, gpointer user_data)
{
    GstMessageType type;

    type = GST_MESSAGE_TYPE (msg);

    switch (type) {
    case GST_MESSAGE_EOS:
      g_debug("EOS");
      destroy_pipeline();
      g_main_loop_quit(loop);
      break;

    case GST_MESSAGE_ERROR:
      {
        GError *error = NULL;
        gchar *debug = NULL;
        gst_message_parse_error(msg, &error, &debug);
        g_error("%s (%d): %s (%s)", g_quark_to_string(error->domain),
                error->code, error->message, debug);
      }
      break;

    case GST_MESSAGE_STATE_CHANGED:
      {
        GstState old_state, new_state, pending_state;
        gst_message_parse_state_changed(msg, &old_state, &new_state,
                                        &pending_state);
        
        if (GST_MESSAGE_SRC(msg) == (gpointer) pipeline)
          {
            g_debug("%s -> %s => %s", gst_element_state_get_name(old_state),
                    gst_element_state_get_name(new_state),
                    gst_element_state_get_name(pending_state));
          }
        break;
      }
    default:
      break;
    }

    return TRUE;
}

static void
set_layers(GESTimeline *timeline)
{
  GESTimelineLayer *audio_layer, *video_layer;
  GESTimelineFileSource *video_source, *audio_source;

  video_layer = GES_TIMELINE_LAYER(ges_simple_timeline_layer_new());
  audio_layer = GES_TIMELINE_LAYER(ges_simple_timeline_layer_new());
  g_object_set(video_layer, "priority", 1, NULL);

  if (!ges_timeline_add_layer(timeline, video_layer) ||
      !ges_timeline_add_layer(timeline, audio_layer))
    {
      g_error("Failed to add the layers, exit now");
    }

  video_source = ges_timeline_filesource_new(video_uri);
  g_object_set(video_source, "in-point", (gint64) 0, "duration", DURATION,
               "mute", TRUE, NULL);

  audio_source = ges_timeline_filesource_new(audio_uri);
  g_object_set(audio_source, "in-point", (gint64) 0, "duration", DURATION,
               "mute", FALSE, NULL);

  ges_timeline_layer_add_object(video_layer, GES_TIMELINE_OBJECT(video_source));
  ges_timeline_layer_add_object(audio_layer, GES_TIMELINE_OBJECT(audio_source));
}

static void
create_pipeline()
{
  GESTimeline *timeline;
  GESTrack *audio_track, *video_track;

  timeline = ges_timeline_new();
  audio_track = ges_track_audio_raw_new();
  video_track = ges_track_video_raw_new();
  
  if (!ges_timeline_add_track(timeline, audio_track) ||
      !ges_timeline_add_track(timeline, video_track))
    {
      g_error("Failed to add the tracks, exit now");
    }

  set_layers(timeline);

#ifndef NO_RESET_LAYERS
  GList *layers, *tmp;

  layers = ges_timeline_get_layers(timeline);

  for (tmp = layers; tmp; tmp = g_list_next(tmp))
    {
      ges_timeline_remove_layer(timeline, GES_TIMELINE_LAYER(tmp->data));
      gst_object_unref(tmp->data);
    }
  g_list_free(layers);

  set_layers(timeline);
#endif

  pipeline = GST_ELEMENT(ges_timeline_pipeline_new());
  
  if (!ges_timeline_pipeline_add_timeline(GES_TIMELINE_PIPELINE(pipeline),
                                          timeline))
    {
      g_error("Failed to add the timeline to the pipeline");
    }
  
  if (!ges_timeline_pipeline_set_mode(GES_TIMELINE_PIPELINE(pipeline),
                                      TIMELINE_MODE_PREVIEW))
    {
      g_error("Failed to set the renderer mode");
    }

  bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
  async_bus_handler_id = gst_bus_add_watch(bus, (GstBusFunc) async_bus_handler,
                                           NULL);
}

static gboolean
start_playback(gpointer data)
{
  gst_element_set_state(pipeline, GST_STATE_PLAYING);
  return FALSE;
}

int
main(int argc, char * argv[])
{
  g_debug("Starting test...");

  if (argc < 3)
    {
      g_error("Usage: ./audio_editing <input_video_uri> <audio_uri>");
    }

  gst_init(&argc, &argv);
  ges_init();

  video_uri = argv[1];
  audio_uri = argv[2];

  create_pipeline();

  g_idle_add(start_playback, NULL);

  loop = g_main_loop_new (NULL, FALSE);
  g_main_loop_run(loop);
  
  return 0;
}
