/* GStreamer
 * Copyright (C) 2003 Thomas Vander Stichele <thomas@apestaart.org>
 *               2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
 *               2005 Andy Wingo <wingo@pobox.com>
 *               2005 Jan Schmidt <thaytan@mad.scientist.com>
 *
 * gst-metadata.c: Use GStreamer to display metadata within files.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */


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

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

static char *filename = NULL;
static GstElement *pipeline = NULL;
static GstElement *source = NULL;

#define NEW_PIPE_PER_FILE

static gboolean
message_loop (GstElement * element, GstTagList ** tags)
{
  GstBus *bus;
  gboolean done = FALSE;

  bus = gst_element_get_bus (element);
  g_return_val_if_fail (bus != NULL, FALSE);
  g_return_val_if_fail (tags != NULL, FALSE);

  while (!done) {
    GstMessage *message;

    message = gst_bus_pop (bus);
    if (message == NULL)
      /* All messages read, we're done */
      break;

    switch (GST_MESSAGE_TYPE (message)) {
      case GST_MESSAGE_ERROR:
      case GST_MESSAGE_EOS:
        gst_message_unref (message);
        return TRUE;
      case GST_MESSAGE_TAG:
      {
        GstTagList *new_tags, *old_tags;

        gst_message_parse_tag (message, &new_tags);
        if (*tags) {
          old_tags = *tags;
          *tags = gst_tag_list_merge (old_tags, new_tags, GST_TAG_MERGE_KEEP);
          gst_tag_list_unref (old_tags);
        } else
          *tags = new_tags;
        break;
      }
      default:
        break;
    }
    gst_message_unref (message);
  }
  gst_object_unref (bus);
  return TRUE;
}

static void
make_pipeline (void)
{
  GstElement *decodebin;

  if (pipeline != NULL)
    gst_object_unref (pipeline);

  pipeline = gst_pipeline_new (NULL);

  source = gst_element_factory_make ("filesrc", "source");
  g_assert (GST_IS_ELEMENT (source));
  decodebin = gst_element_factory_make ("decodebin", "decodebin");
  g_assert (GST_IS_ELEMENT (decodebin));

  gst_bin_add_many (GST_BIN (pipeline), source, decodebin, NULL);
  gst_element_link (source, decodebin);
}

static void
print_tag (const GstTagList * list, const gchar * tag, gpointer unused)
{
  gint i, count;

  count = gst_tag_list_get_tag_size (list, tag);

  for (i = 0; i < count; i++) {
    gchar *str;

    if (gst_tag_get_type (tag) == G_TYPE_STRING) {
      if (!gst_tag_list_get_string_index (list, tag, i, &str))
        g_assert_not_reached ();
    } else {
      str =
          g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i));
    }

    if (i == 0) {
      g_print ("  %15s: %s\n", gst_tag_get_nick (tag), str);
    } else {
      g_print ("                 : %s\n", str);
    }

    g_free (str);
  }
}

int
main (int argc, char *argv[])
{
  guint i = 1;

  setlocale (LC_ALL, "");

  gst_init (&argc, &argv);

  if (argc < 2) {
    g_print ("Please give filenames to read metadata from\n\n");
    return 1;
  }

  make_pipeline ();
  while (i < argc) {
    GstStateChangeReturn sret;
    GstState state;
    GstTagList *tags = NULL;

    filename = argv[i];
    g_object_set (source, "location", filename, NULL);

    GST_DEBUG ("Starting reading for %s", filename);

    /* Decodebin will only commit to PAUSED if it actually finds a type;
     * otherwise the state change fails */
    sret = gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PAUSED);

    if (GST_STATE_CHANGE_ASYNC == sret) {
      if (GST_STATE_CHANGE_SUCCESS !=
          gst_element_get_state (GST_ELEMENT (pipeline), &state, NULL,
              5 * GST_SECOND)) {
        g_print ("State change failed for %s. Aborting\n", filename);
        break;
      }
    } else if (sret != GST_STATE_CHANGE_SUCCESS) {
      g_print ("%s - Could not read file\n", filename);
      goto next_file;
    }

    if (!message_loop (GST_ELEMENT (pipeline), &tags)) {
      g_print ("Failed in message reading for %s\n", argv[i]);
    }

    if (tags) {
      g_print ("Metadata for %s:\n", argv[i]);
      gst_tag_list_foreach (tags, print_tag, NULL);
      gst_tag_list_unref (tags);
      tags = NULL;
    } else
      g_print ("No metadata found for %s\n", argv[i]);

    sret = gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
#ifdef NEW_PIPE_PER_FILE
    if (sret != GST_STATE_CHANGE_SUCCESS) {
      g_print ("State change failed. Aborting\n");
      break;
    }
#else
    if (GST_STATE_CHANGE_ASYNC == sret) {
      if (GST_STATE_CHANGE_FAILURE ==
          gst_element_get_state (GST_ELEMENT (pipeline), &state, NULL,
              GST_CLOCK_TIME_NONE)) {
        g_print ("State change failed. Aborting");
        break;
      }
    } else if (sret != GST_STATE_CHANGE_SUCCESS) {
      g_print ("State change failed. Aborting\n");
      break;
    }
#endif

  next_file:
    i++;

#ifdef NEW_PIPE_PER_FILE
    make_pipeline ();
#endif
  }

  if (pipeline)
    gst_object_unref (pipeline);
  return 0;
}
