/***************************************************************************
 *
 * Copyright (c) 2000, 2001 BalaBit IT Ltd, Budapest, Hungary
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: registry.c,v 1.10.6.3 2001/09/19 19:22:17 bazsi Exp $
 *
 * Author  : Bazsi
 * Auditor : kisza
 * Last version: 1.8
 * Notes:
 *
 ***************************************************************************/

#include <zorp/registry.h>
#include <zorp/log.h>
#include <glib.h>

static GHashTable *registry[MAX_REGISTRY_TYPE];

#define MAX_REGISTRY_NAME 32

/*+

  An entry in the registry. The registry is a hash table indexed by a
  string and storing an opaque pointer and an integer type
  value. ZRegistryEntry is an entry in the registry hash.

  +*/
typedef struct _ZRegistryEntry
{
  gint type;
  gchar name[MAX_REGISTRY_NAME];
  gpointer value;
} ZRegistryEntry;

/*+

  Initialize the registry subsystem.

  Parameters:
    none

  Returns:
    none

  +*/
void
z_registry_init(void)
{
  int i;
  for (i=0; i<MAX_REGISTRY_TYPE; i++)
    registry[i] = g_hash_table_new(g_str_hash,
			      g_str_equal);
}


/*+

  Deinitialize the registry subsystem.

  Parameters:
    none

  Returns:
    none

  +*/
void
z_registry_destroy(void)
{
  int i;
  for (i=0; i<MAX_REGISTRY_TYPE; i++)
    g_hash_table_destroy(registry[i]);
}

/*+

  Add an entry to the registry with the given name and type.

  Parameters:
    name       the key of this entry
    type       the type of this entry
    value      the pointer associated with this entry

  Returns:
    none

  +*/
void
z_registry_add(gchar *name, gint type, gpointer value)
{
  ZRegistryEntry *ze = g_new0(ZRegistryEntry, 1);

  if (type < 0 || type > MAX_REGISTRY_TYPE)
    {
      /*LOG
        This message indicates an internal error and should be treated as
        such. An buggy/incompatible loadable module might want to register
        an unsupported module type.
       */
      z_log(NULL, CORE_ERROR, 0, "Internal error. Bad registry type;");
      return;
    }
  strncpy(ze->name, name, sizeof(ze->name));
  ze->value = value;
  ze->type = type;
  g_hash_table_insert(registry[type], ze->name, ze);
}

/*+

  Fetch an item from the registry with the given name returning its
  type and pointer.

  Parameters:
    name      name of the entry to fetch
    type      pointer to an int, where the type of the entry is stored.

  Returns:
    NULL if the entry was not found, the associated pointer otherwise

  +*/
  
ZRegistryEntry *
z_registry_get_one(gchar *name, gint type)
{
  ZRegistryEntry *ze = NULL;
  
  z_enter();
  ze = g_hash_table_lookup(registry[type], name);
  z_leave();
  return ze;
}

gpointer
z_registry_get(gchar *name, gint *type)
{
  int i;
  ZRegistryEntry *ze = NULL;
  
  z_enter();
  if (type && (*type > MAX_REGISTRY_TYPE || *type < 0))
    {
      z_leave();
      return NULL;
    }
  if (type == NULL || *type == 0)
    {
      for (i=0; i < MAX_REGISTRY_TYPE && ze == NULL; i++)
        {
          ze = z_registry_get_one(name, i);
        }
    }
  else
    {
      ze = z_registry_get_one(name, *type);
    }
    
  if (ze)
    {
      if (type) 
        *type = ze->type;
      z_leave();
      return ze->value;
    }
  z_leave();
  return NULL;    
}

guint
z_registry_has_key(gchar *name)
{
  int i;
  ZRegistryEntry *ze = NULL;
  
  for (i=0; (i < MAX_REGISTRY_TYPE) && (ze == NULL); i++)
    {
      ze = z_registry_get_one(name, i);
    }
  if (ze)
    {
      return i;
    }
  else
    {
      return 0;
    }
}