/* stuff - a content retrieval and management experiment.
 *
 * Copyright Øyvind Kolås <pippin@gimp.org> 2007-2008
 * Licensed under the LGPL v2 or greater.
 */

#include <unistd.h>
#include <glib.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>
#include "string.h"
#include <sys/types.h>
#include <sys/stat.h>

/*#ifdef g_lstat
 #undef g_lstat
 #endif
 #define g_lstat g_stat*/

#define SKIP_DOT

static gboolean g_recursive;
static gint     g_level;
static gboolean (*g_func
                 )(gpointer item,
                   gboolean recursive,
                   gint level,
                   struct stat *stat_buf,
                   gpointer     user_data);
static gpointer g_user_data;
static gint     g_elements    = 0;
static GSList  *pending       = NULL;
static GSList  *pending_level = NULL;


void
stuff_tree_digger_lazy_init (
                        const gchar *path,
                        gboolean     recursive,
                        gint         level,
                        gboolean   (*func)(gpointer
                                            item,
                                            gboolean
                                            recursive,
                                            gint
                                            level,
                                            struct stat
                                            *stat_buf,
                                            gpointer
                                            user_data),
                        gpointer     user_data)
{
  pending     = g_slist_prepend (pending, g_strdup (path));
  g_recursive = recursive;
  g_level     = level;
  g_func      = func;
  g_user_data = user_data;

  pending_level = g_slist_prepend (pending_level, GINT_TO_POINTER (level));
}

/* return TRUE if there is more work */
gboolean
stuff_tree_digger_lazy_dig (void)
{
  gint          level;
  gchar        *path;
  GDir         *dir;
  gint          path_len;
  const gchar  *fname;
  gchar        *full_path;
  struct stat   stat_buf;

  if (pending == NULL)
    return FALSE;

  level = GPOINTER_TO_INT (pending_level->data);
  path  = pending->data;

  pending       = g_slist_remove (pending, path);
  pending_level = g_slist_remove (pending_level, GINT_TO_POINTER (level));

  path_len = strlen (path);
  dir      = g_dir_open (path, 0, NULL);

  if (!dir)
    {
      g_free (path);
      return TRUE;
    }

  full_path = g_malloc (path_len + 512 + 1);

  while ((fname = g_dir_read_name (dir)))
    {
#ifdef SKIP_DOT
      if (fname[0] == '.')
        continue;
#endif
      if (g_str_equal (path, "/"))
        {
          g_snprintf (full_path, path_len + 512,
                      "/%s", fname);
        }
      else
        {
          g_snprintf (full_path, path_len + 512,
                      "%s/%s", path, fname);
        }
      if (g_lstat (full_path, &stat_buf) == 0)
        {
          if (g_func (full_path, g_recursive, level, &stat_buf, g_user_data))
            {
              if (g_recursive &&
                  S_ISDIR (stat_buf.st_mode))
                {
                  pending       = g_slist_prepend (pending, g_strdup (full_path));
                  pending_level = g_slist_prepend (pending_level,
                                                   GINT_TO_POINTER (
                                                     level + 1));
                }
              g_elements++;
            }
        }
    }

  g_dir_close (dir);
  g_free (full_path);
  g_free (path);
  return TRUE;
}

gint
stuff_tree_digger (const gchar  *path,
                   gboolean      recursive,
                   gint          level,
                   gboolean    (*func)(gpointer item,
                                       gboolean     recursive,
                                       gint         level,
                                       struct stat *stat_buf,
                                       gpointer     user_data),
                   gpointer      user_data)
{
  g_elements = 0;
  lazy_digger_init (path, recursive, level, func, user_data);
  while (lazy_digger_dig ()) ;
  return g_elements;
}

gboolean
stuff_tree_digger_print_element (gpointer     path,
                                 gboolean     recursive,
                                 gint         level,
                                 struct stat *stat_buf,
                                 gpointer     user_data)
{
  gboolean is_regular;
  gboolean is_dir;

  is_dir     = S_ISDIR (stat_buf->st_mode);
  is_regular = S_ISREG (stat_buf->st_mode);

  g_printf ("%s, %p%s%s %i\n", path, user_data,
            is_dir ? " (dir)" : "",
            is_regular ? " (regular)" : "",
            stat_buf->st_mode);

  return TRUE;
}
