/*****
 NAME
	cidhash.m - source code for CIdHash class
 VERSION
	$Id$
 CHANGELOG
	$Log$
 */

#include <coconut/cidhash.h>
#include <coconut/csystem.h>
#include <coconut/ptext.h>
#include <coconut/fobject.h>

static void foreach_norm1_func(gpointer key, gpointer value, gpointer user) ;
static void foreach_norm2_func(gpointer key, gpointer value, gpointer user) ;
static void foreach_hash1_func(gpointer key, gpointer value, gpointer user) ;
static void foreach_hash2_func(gpointer key, gpointer value, gpointer user) ;
static void foreach_print(gpointer key, gpointer value, gpointer userdata) ;

static gboolean remove_hash_elm(gpointer key, gpointer value, gpointer user) ;

@implementation CIdHash 

- init
{
	return [self initIdHash: &g_str_hash equalKeyFunc: &g_str_equal
	  removeKeyFunc: &remove_nothing_func] ;
}

- initIdHash: (hash_func_t) hashf equalKeyFunc: (equal_func_t) equalkey
    removeKeyFunc: (remove_func_t) removekey
{
	hash_table = g_hash_table_new_full(hashf, equalkey, removekey,
	  &remove_object_func);
	[CSystem checkPtr: hash_table] ;
	return [super init] ;
}

- (void) dealloc
{
	g_hash_table_destroy(hash_table) ;
	[super dealloc] ;
}

- (u_int) count
{
	return g_hash_table_size(hash_table) ;
}

- clear
{
	g_hash_table_foreach_remove(hash_table, &remove_hash_elm, NULL) ;
	return nil ;
}

- foreach: (SEL) msg with: p1 with: p2
{
	signal_t	signal ;

	SET_SIGNAL(signal, nil, msg, p1, p2) ;
	g_hash_table_foreach(hash_table, &foreach_norm1_func, &signal) ;
	return nil ;
}

- foreach: (id) obj message: (SEL) msg with: p1 
{
	signal_t	signal ;

	SET_SIGNAL(signal, obj, msg, p1, nil) ;
	g_hash_table_foreach(hash_table, &foreach_norm2_func, &signal) ;
	return nil ;
}

- foreachHash: (SEL) msg with: p1 
{
	signal_t	signal ;

	SET_SIGNAL(signal, nil, msg, p1, nil) ;
	g_hash_table_foreach(hash_table, &foreach_hash1_func, &signal) ;
	return nil ;
}

- foreachHash: (id) obj message: (SEL) msg 
{
	signal_t	signal ;

	SET_SIGNAL(signal, obj, msg, nil, nil) ;
	g_hash_table_foreach(hash_table, &foreach_hash2_func, &signal) ;
	return nil ;
}

- add: (const void *) key object: (id) obj
{
	[obj retain] ;
	g_hash_table_insert(hash_table, (gpointer) key, (gpointer) obj) ;
	return nil ;
}

- (id) search: (const void *) key
{
	/* the function g_hash_table_lookup causes segmentation fault 
	   when the parameter key is null pointer */
	return key ? g_hash_table_lookup(hash_table, (gpointer) key) : NULL ;
}

- print: (id <PIndentStream>) stream 
{
	[stream putPtr: "(hash\n"] ;
	[stream incLevel] ;
	  g_hash_table_foreach(hash_table, &foreach_print, stream) ;
	[stream decLevel] ;
	[stream putPtr: ")\n"] ;
	return nil ;
}

@end

static void foreach_norm1_func(gpointer key, gpointer value, gpointer userdata)
{
	signal_t *	sig = (signal_t *) userdata ;
	[((id)value) perform: sig->message with: sig->param1 with: sig->param2];
}

static void foreach_norm2_func(gpointer key, gpointer value, gpointer userdata)
{
	signal_t *	sig = (signal_t *) userdata ;
	[sig->obj perform: sig->message with: value with: sig->param1] ;
}

static void foreach_hash1_func(gpointer key, gpointer value, gpointer userdata)
{
	signal_t *	sig = (signal_t *) userdata ;
	[((id)value) perform: sig->message with: key with: sig->param1] ;
}

static void foreach_hash2_func(gpointer key, gpointer value, gpointer userdata)
{
	signal_t *	sig = (signal_t *) userdata ;
	[sig->obj perform: sig->message with: key with: value] ;
}

static void foreach_print(gpointer key, gpointer value, gpointer userdata)
{
	id <PIndentStream>	stream = (id <PIndentStream>) userdata ;
	[((id)value) print: stream] ;
	[stream putChar: '\n'] ;
}

static gboolean remove_hash_elm(gpointer key, gpointer value, gpointer user)
{
	return 1 ; /* always remove ok */
}

