/* GStreamer
 *
 * Copyright (C) 2005 Lutz Mueller <lutz@topfrose.de>
 * 
 * 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,
 * dirut 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., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "gstdirsrc.h"

GST_DEBUG_CATEGORY_STATIC (dir_src_debug);
#define GST_CAT_DEFAULT dir_src_debug

static GstElementDetails dir_src_details = GST_ELEMENT_DETAILS (
    "Directory reader", "Source/Directory",
    "Read contents of directories", "Lutz Mueller <lutz@topfrose.de>");

struct _GstDirSrc
{
  GstBin parent;

  gchar *location;
};

struct _GstDirSrcClass
{
  GstBinClass parent_class;
};

enum {
  PROP_0 = 0,
  PROP_LOCATION
};

GST_BOILERPLATE (GstDirSrc, gst_dir_src, GstBin, GST_TYPE_BIN);

static void
foreach_remove (gpointer data, gpointer user_data)
{
  gst_bin_remove (GST_BIN (user_data), GST_ELEMENT (data));
}

static gboolean
gst_dir_src_set_location (GstDirSrc * dir, const gchar * location)
{
  GstIterator *it;
  GDir *gdir;
  const gchar *entry;

  if ((!dir->location && !location) ||
      (dir->location && location && !strcmp (location, dir->location)))
    return TRUE;

  it = gst_bin_iterate_elements (GST_BIN (dir));
  gst_iterator_foreach (it, foreach_remove, dir);
  gst_iterator_free (it);
  if (dir->location) {
    g_free (dir->location);
    dir->location = NULL;
  }
  if (!location)
    return TRUE;

  if (!g_file_test (location, G_FILE_TEST_IS_DIR)) {
    GST_DEBUG_OBJECT (dir, "'%s' is not a directory.", location);
    return FALSE;
  }
  gdir = g_dir_open (location, 0, NULL);
  if (!gdir) {
    GST_DEBUG_OBJECT (dir, "Could not open directory '%s'.", location);
    return FALSE;
  }
  while (entry = g_dir_read_name (gdir)) {
    gchar *path;

    GST_DEBUG_OBJECT (dir, "Found '%s'.", entry);
    path = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", location, entry);
    if (g_file_test (path, G_FILE_TEST_IS_REGULAR)) {
      GstElement *element;

      if (!(element = gst_element_factory_make ("filesrc", NULL))) {
        GST_DEBUG_OBJECT (dir, "Could not create element for '%s'.", path);
      } else {
        GstPad *pad;

        pad = gst_element_get_pad (element, "src");
        gst_element_add_pad (GST_ELEMENT (dir),
            gst_ghost_pad_new (path, pad));
        gst_object_unref (GST_OBJECT (pad));
        g_object_set (G_OBJECT (element), "location", path, NULL);
        gst_bin_add (GST_BIN (dir), element);
      }
    }
    g_free (path);
  }
  g_dir_close (gdir);
  gst_element_no_more_pads (GST_ELEMENT (dir));

  dir->location = g_strdup (location);
  return TRUE;
}

static void
gst_dir_src_init (GstDirSrc * dir, GstDirSrcClass * klass)
{
}

static GstStaticPadTemplate t =
GST_STATIC_PAD_TEMPLATE ("src_%d", GST_PAD_SRC, GST_PAD_SOMETIMES,
    GST_STATIC_CAPS_ANY);

static void
gst_dir_src_base_init (gpointer g_class)
{
  GstElementClass *ec = GST_ELEMENT_CLASS (g_class);

  gst_element_class_add_pad_template (ec, gst_static_pad_template_get (&t));
  gst_element_class_set_details (ec, &dir_src_details);
}

static void
gst_dir_src_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstDirSrc *dir = GST_DIR_SRC (object);

  switch (prop_id) {
    case PROP_LOCATION:
      g_value_set_string (value, dir->location);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  }
}

static void
gst_dir_src_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstDirSrc *dir = GST_DIR_SRC (object);

  switch (prop_id) {
    case PROP_LOCATION:
      gst_dir_src_set_location (dir, g_value_get_string (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  }
}

static void
gst_dir_src_finalize (GObject * object)
{
  GstDirSrc *dir = GST_DIR_SRC (object);

  if (dir->location) {
    g_free (dir->location);
    dir->location = NULL;
  }

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
gst_dir_src_class_init (GstDirSrcClass * klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->get_property = gst_dir_src_get_property;
  gobject_class->set_property = gst_dir_src_set_property;
  gobject_class->finalize = gst_dir_src_finalize;

  g_object_class_install_property (gobject_class,
      PROP_LOCATION, g_param_spec_string ("location",
        "Directory Location", "Location of the directory to read from",
        NULL, G_PARAM_READWRITE));

  GST_DEBUG_CATEGORY_INIT (dir_src_debug, "dirsrc", 0, "Directory reader");
}
