/* tidy-actor.h: Base class for Tidy actors
 *
 * Copyright (C) 2007 OpenedHand
 *
 * 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 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.
 */

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

#include <glib-object.h>

#include "tidy-texture-cache.h"
#include "tidy-private.h"

G_DEFINE_TYPE (TidyTextureCache, tidy_texture_cache, G_TYPE_OBJECT)

#define TEXTURE_CACHE_PRIVATE(o) \
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), TIDY_TYPE_TEXTURE_CACHE, TidyTextureCachePrivate))

typedef struct _TidyTextureCachePrivate TidyTextureCachePrivate;

struct _TidyTextureCachePrivate
{
  GHashTable *cache;
};

typedef struct FinalizedClosure
{
  gchar             *path;
  TidyTextureCache  *cache;
} FinalizedClosure;

static TidyTextureCache* __cache_singleton = NULL;

static void
tidy_texture_cache_dispose (GObject *object)
{
  if (G_OBJECT_CLASS (tidy_texture_cache_parent_class)->dispose)
    G_OBJECT_CLASS (tidy_texture_cache_parent_class)->dispose (object);
}

static void
tidy_texture_cache_finalize (GObject *object)
{
  G_OBJECT_CLASS (tidy_texture_cache_parent_class)->finalize (object);
}

static void
tidy_texture_cache_class_init (TidyTextureCacheClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  g_type_class_add_private (klass, sizeof (TidyTextureCachePrivate));

  object_class->dispose = tidy_texture_cache_dispose;
  object_class->finalize = tidy_texture_cache_finalize;
}

static void
tidy_texture_cache_init (TidyTextureCache *self)
{
  TidyTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(self);

  priv->cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}

TidyTextureCache*
tidy_texture_cache_get_default (void)
{
  if (G_UNLIKELY (__cache_singleton == NULL))
    __cache_singleton = g_object_new (TIDY_TYPE_TEXTURE_CACHE, NULL);
  
  return  __cache_singleton;
}

void
on_texure_finalized (gpointer data,
		     GObject *where_the_object_was)
{
  FinalizedClosure *closure = (FinalizedClosure *)data;
  TidyTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(closure->cache);

  g_hash_table_remove (priv->cache, closure->path);

  g_free(closure->path);
  g_free(closure);
}

gint
tidy_texture_cache_get_size (TidyTextureCache *self)
{
  TidyTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(self);

  return g_hash_table_size (priv->cache);
}

/* NOTE: you should unref the returned texture when not needed */
ClutterActor*
tidy_texture_cache_get_texture (TidyTextureCache *self,
				const gchar      *path, 
				gboolean          want_clone)
{
  TidyTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(self);
  ClutterActor *res;

  res = g_hash_table_lookup (priv->cache, path);

  if (!res)
    {
      FinalizedClosure *closure;

      res = clutter_texture_new_from_file (path, NULL);
      if (!res)
	return NULL;

      g_hash_table_insert (priv->cache, g_strdup (path), res);

      /* Make sure we can remove from hash */
      closure = g_new0(FinalizedClosure, 1);
      closure->path = g_strdup(path);
      closure->cache = self;

      g_object_weak_ref (G_OBJECT (res), on_texure_finalized, closure);
    }
  else
    {
      /* If its a lookup, then increase the ref count */
      if (!want_clone)  /* clones already ref the parent */
        g_object_ref (res);
    }

  if (want_clone)
    res = clutter_clone_texture_new (CLUTTER_TEXTURE (res));

  return res;
}

