The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/*
 * Copyright (C) 2005 by the gtk2-perl team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id$
 */

#include "gst2perl.h"

/* ------------------------------------------------------------------------- */

static GPerlBoxedWrapperClass gst_tag_list_wrapper_class;

static void
fill_hv (const GstTagList *list,
         const gchar *tag,
         gpointer user_data)
{
	HV *hv = (HV *) user_data;
	AV *av = newAV ();
	guint size, i;

	size = gst_tag_list_get_tag_size (list, tag);
	for (i = 0; i < size; i++) {
		const GValue *value;
		SV *sv;

		value = gst_tag_list_get_value_index (list, tag, i);
		sv = gperl_sv_from_value (value);

		av_store (av, i, sv);
	}

	hv_store (hv, tag, strlen (tag), newRV_noinc ((SV *) av), 0);
}

static SV *
gst_tag_list_wrap (GType gtype,
                   const char *package,
                   GstTagList *list,
		   gboolean own)
{
	HV *hv = newHV ();

	gst_tag_list_foreach (list, fill_hv, hv);
	if (own)
		gst_tag_list_free (list);

	return newRV_noinc ((SV *) hv);
}

static GstTagList *
gst_tag_list_unwrap (GType gtype,
                     const char *package,
                     SV *sv)
{
	/* FIXME: Do we leak the list? */
	GstTagList *list = gst_tag_list_new ();
	HV *hv = (HV *) SvRV (sv);
	HE *he;

	hv_iterinit (hv);
	while (NULL != (he = hv_iternext (hv))) {
		I32 length, i;
		char *tag;
		GType type;
		SV *ref;
		AV *av;

		tag = hv_iterkey (he, &length);
		if (!gst_tag_exists (tag))
			continue;

		ref = hv_iterval (hv, he);
		if (!gperl_sv_is_array_ref (ref))
			croak ("The values inside of GstTagList's have to be array references");

		type = gst_tag_get_type (tag);

		av = (AV *) SvRV (ref);
		for (i = 0; i <= av_len (av); i++) {
			GValue value = { 0 };
			SV **entry = av_fetch (av, i, 0);

			if (!(entry && gperl_sv_is_defined (*entry)))
				continue; /* FIXME: Why not croak here, too? */

			g_value_init (&value, type);
			gperl_value_from_sv (&value, *entry);

			gst_tag_list_add_values (list, GST_TAG_MERGE_APPEND, tag, &value, NULL);

			g_value_unset (&value);
		}
	}

	return list;
}

/* ------------------------------------------------------------------------- */

MODULE = GStreamer::Tag	PACKAGE = GStreamer::Tag	PREFIX = gst_tag_

BOOT:
	gst_tag_list_wrapper_class = *gperl_default_boxed_wrapper_class ();
	gst_tag_list_wrapper_class.wrap = (GPerlBoxedWrapFunc) gst_tag_list_wrap;
	gst_tag_list_wrapper_class.unwrap = (GPerlBoxedUnwrapFunc) gst_tag_list_unwrap;
	gperl_register_boxed (GST_TYPE_TAG_LIST, "GStreamer::TagList",
	                      &gst_tag_list_wrapper_class);
	gperl_set_isa ("GStreamer::TagList", "Glib::Boxed");

# FIXME: Might be handy.  But GstTagMergeFunc looks ugly.
# void gst_tag_register (const gchar * name, GstTagFlag flag, GType type, const gchar * nick, const gchar * blurb, GstTagMergeFunc func);

# void gst_tag_merge_use_first (GValue * dest, const GValue * src);
# void gst_tag_merge_strings_with_comma (GValue * dest, const GValue * src);

=for apidoc __function__
=cut
gboolean gst_tag_exists (const gchar * tag);

=for apidoc __function__
=cut
# GType gst_tag_get_type (const gchar * tag);
const char *
gst_tag_get_type (tag)
	const gchar * tag
    CODE:
	RETVAL = gperl_package_from_type (gst_tag_get_type (tag));
    OUTPUT:
	RETVAL

=for apidoc __function__
=cut
const gchar * gst_tag_get_nick (const gchar * tag);

=for apidoc __function__
=cut
const gchar * gst_tag_get_description (const gchar * tag);

=for apidoc __function__
=cut
GstTagFlag gst_tag_get_flag (const gchar * tag);

=for apidoc __function__
=cut
gboolean gst_tag_is_fixed (const gchar * tag);