/*
 * Copyright © 2008 Ryan Lortie
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of version 3 of the GNU General Public License as
 * published by the Free Software Foundation.   
 */

#include "trashexpunge.h"

static gsize trash_expunge_initialised;
static GHashTable *trash_expunge_queue;
static gboolean trash_expunge_alive;
static GMutex trash_expunge_lock;
static GCond trash_expunge_wait;

static void
trash_expunge_delete_everything_under (GFile *directory)
{
  GFileEnumerator *enumerator;

  g_file_set_attribute_uint32 (directory,
                               G_FILE_ATTRIBUTE_UNIX_MODE, 0700,
                               G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                               NULL, NULL);

  enumerator = g_file_enumerate_children (directory,
                                          G_FILE_ATTRIBUTE_STANDARD_NAME ","
                                          G_FILE_ATTRIBUTE_STANDARD_TYPE,
                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                          NULL, NULL);

  if (enumerator)
    {
      GFileInfo *info;

      while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)))
        {
          const gchar *basename;
          GFile *sub;
          
          basename = g_file_info_get_name (info);
          sub = g_file_get_child (directory, basename);

          if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
            trash_expunge_delete_everything_under (sub);

          /* do the delete here */
          g_file_delete (sub, NULL, NULL);

          g_object_unref (info);
          g_object_unref (sub);
        }
      g_object_unref (enumerator);
    }
}

static gboolean
just_return_true (gpointer a,
                  gpointer b,
                  gpointer c)
{
  return TRUE;
}

static gpointer
trash_expunge_thread (gpointer data)
{
  gint64 end_time;

  g_mutex_lock (&trash_expunge_lock);

  do
    {
      while (g_hash_table_size (trash_expunge_queue))
        {
          GFile *directory;
         
          directory = g_hash_table_find (trash_expunge_queue,
                                         just_return_true, NULL);
          g_hash_table_remove (trash_expunge_queue, directory);

          g_mutex_unlock (&trash_expunge_lock);
          trash_expunge_delete_everything_under (directory);
          g_mutex_lock (&trash_expunge_lock);

          g_object_unref (directory);
        }

      end_time = g_get_monotonic_time () + 1 * G_TIME_SPAN_MINUTE;
    }
  while (g_cond_wait_until (&trash_expunge_wait,
                            &trash_expunge_lock,
                            end_time));

  trash_expunge_alive = FALSE;

  g_mutex_unlock (&trash_expunge_lock);

  return NULL;
}

void
trash_expunge (GFile *directory)
{
  if G_UNLIKELY (g_once_init_enter (&trash_expunge_initialised))
    {
      trash_expunge_queue = g_hash_table_new (g_file_hash,
                                              (GEqualFunc) g_file_equal);
      g_once_init_leave (&trash_expunge_initialised, 1);
    }

  g_mutex_lock (&trash_expunge_lock);

  if (!g_hash_table_lookup (trash_expunge_queue, directory))
    g_hash_table_insert (trash_expunge_queue,
                         g_object_ref (directory),
                         directory);

  if (trash_expunge_alive == FALSE)
    {
      GThread *thread;

      thread = g_thread_new ("trash-expunge", trash_expunge_thread, NULL);
      g_assert (thread != NULL);
      trash_expunge_alive = TRUE;
    }
  else
    g_cond_signal (&trash_expunge_wait);

  g_mutex_unlock (&trash_expunge_lock);
}
