/* GStreamer
 *
 * Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
 * Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
 *
 * 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.
 */

/**
 * SECTION:gstplayer-visualization
 * @title: GstPlayerVisualization
 * @short_description: Player Visualization
 *
 */

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

#include "gstplayer-visualization.h"

#include <string.h>

static GMutex vis_lock;
static GQueue vis_list = G_QUEUE_INIT;
static guint32 vis_cookie;

G_DEFINE_BOXED_TYPE (GstPlayerVisualization, gst_player_visualization,
    (GBoxedCopyFunc) gst_player_visualization_copy,
    (GBoxedFreeFunc) gst_player_visualization_free);

/**
 * gst_player_visualization_free:
 * @vis: #GstPlayerVisualization instance
 *
 * Frees a #GstPlayerVisualization.
 */
void
gst_player_visualization_free (GstPlayerVisualization * vis)
{
  g_return_if_fail (vis != NULL);

  g_free (vis->name);
  g_free (vis->description);
  g_free (vis);
}

/**
 * gst_player_visualization_copy:
 * @vis: #GstPlayerVisualization instance
 *
 * Makes a copy of the #GstPlayerVisualization. The result must be
 * freed using gst_player_visualization_free().
 *
 * Returns: (transfer full): an allocated copy of @vis.
 */
GstPlayerVisualization *
gst_player_visualization_copy (const GstPlayerVisualization * vis)
{
  GstPlayerVisualization *ret;

  g_return_val_if_fail (vis != NULL, NULL);

  ret = g_new0 (GstPlayerVisualization, 1);
  ret->name = vis->name ? g_strdup (vis->name) : NULL;
  ret->description = vis->description ? g_strdup (vis->description) : NULL;

  return ret;
}

/**
 * gst_player_visualizations_free:
 * @viss: a %NULL terminated array of #GstPlayerVisualization to free
 *
 * Frees a %NULL terminated array of #GstPlayerVisualization.
 */
void
gst_player_visualizations_free (GstPlayerVisualization ** viss)
{
  GstPlayerVisualization **p;

  g_return_if_fail (viss != NULL);

  p = viss;
  while (*p) {
    g_free ((*p)->name);
    g_free ((*p)->description);
    g_free (*p);
    p++;
  }
  g_free (viss);
}

static void
gst_player_update_visualization_list (void)
{
  GList *features;
  GList *l;
  guint32 cookie;
  GstPlayerVisualization *vis;

  g_mutex_lock (&vis_lock);

  /* check if we need to update the list */
  cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
  if (vis_cookie == cookie) {
    g_mutex_unlock (&vis_lock);
    return;
  }

  /* if update is needed then first free the existing list */
  while ((vis = g_queue_pop_head (&vis_list)))
    gst_player_visualization_free (vis);

  features = gst_registry_get_feature_list (gst_registry_get (),
      GST_TYPE_ELEMENT_FACTORY);

  for (l = features; l; l = l->next) {
    GstPluginFeature *feature = l->data;
    const gchar *klass;

    klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY (feature),
        GST_ELEMENT_METADATA_KLASS);

    if (strstr (klass, "Visualization")) {
      vis = g_new0 (GstPlayerVisualization, 1);

      vis->name = g_strdup (gst_plugin_feature_get_name (feature));
      vis->description =
          g_strdup (gst_element_factory_get_metadata (GST_ELEMENT_FACTORY
              (feature), GST_ELEMENT_METADATA_DESCRIPTION));
      g_queue_push_tail (&vis_list, vis);
    }
  }
  gst_plugin_feature_list_free (features);

  vis_cookie = cookie;

  g_mutex_unlock (&vis_lock);
}

/**
 * gst_player_visualizations_get:
 *
 * Returns: (transfer full) (array zero-terminated=1) (element-type GstPlayerVisualization):
 *  a %NULL terminated array containing all available
 *  visualizations. Use gst_player_visualizations_free() after
 *  usage.
 */
GstPlayerVisualization **
gst_player_visualizations_get (void)
{
  gint i = 0;
  GList *l;
  GstPlayerVisualization **ret;

  gst_player_update_visualization_list ();

  g_mutex_lock (&vis_lock);
  ret = g_new0 (GstPlayerVisualization *, g_queue_get_length (&vis_list) + 1);
  for (l = vis_list.head; l; l = l->next)
    ret[i++] = gst_player_visualization_copy (l->data);
  g_mutex_unlock (&vis_lock);

  return ret;
}