/* This is -*- C -*- */
/* $Id: guppi-struct-core.c,v 1.1 2002/01/08 06:29:00 trow Exp $ */

/*
 * guppi-struct-core-impl.c
 *
 * Copyright (C) 2000 EMC Capital Management, Inc.
 * Copyright (C) 2001 The Free Software Foundation
 *
 * Developed by Jon Trowbridge <trow@gnu.org> and
 * Havoc Pennington <hp@pobox.com>.
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#include <config.h>
#include "guppi-struct-core.h"

#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>

#include <guppi-convenient.h>
#include <guppi-memory.h>

static GtkObjectClass *parent_class = NULL;

typedef struct _GuppiStructField GuppiStructField;
struct _GuppiStructField {
  GtkType type;
  GuppiData *data;
};

static void
hash_free (gpointer key, gpointer val, gpointer user_data)
{
  GuppiStructField *f = (GuppiStructField *) val;

  guppi_unref0 (f->data);
  guppi_free (key);
  guppi_free (val);
}

static void
guppi_struct_core_destroy (GtkObject *obj)
{
  GuppiStructCore *core = GUPPI_STRUCT_CORE (obj);

  if (parent_class->destroy)
    parent_class->destroy (obj);


  g_hash_table_foreach (core->fields, hash_free, NULL);
  g_hash_table_destroy (core->fields);
  g_list_free (core->field_names);
  core->fields = NULL;
}

static void
guppi_struct_core_finalize (GtkObject *obj)
{
  if (parent_class->finalize)
    parent_class->finalize (obj);
}

/***************************************************************************/

static gboolean
v_struct_add_field (GuppiStruct *str, const gchar *field, GtkType t)
{
  GuppiStructCore *core = GUPPI_STRUCT_CORE (str);
  GuppiStructField *p;
  gchar *dup_field;

  p = (GuppiStructField *) g_hash_table_lookup (core->fields, field);
  if (p != NULL)
    return FALSE;

  ++core->field_count;
  dup_field = guppi_strdup (field);
  core->field_names = g_list_append (core->field_names, dup_field);

  p = guppi_new (GuppiStructField, 1);
  p->type = t;
  p->data = NULL;
  g_hash_table_insert (core->fields, dup_field, p);

  return TRUE;
}

static GtkType
v_struct_field_type (GuppiStruct *str, const gchar *field)
{
  GuppiStructCore *core = GUPPI_STRUCT_CORE (str);
  GuppiStructField *p;

  p = (GuppiStructField *) g_hash_table_lookup (core->fields, field);
  if (p == NULL)
    return (GtkType) 0;
  return p->type;
}

static GuppiData *
v_struct_get (GuppiStruct *str, const gchar *field)
{
  GuppiStructCore *core = GUPPI_STRUCT_CORE (str);
  GuppiStructField *p;

  p = (GuppiStructField *) g_hash_table_lookup (core->fields, field);
  return p ? p->data : NULL;
}

static gboolean
v_struct_set (GuppiStruct *str, const gchar *field, GuppiData *data)
{
  GuppiStructCore *core = GUPPI_STRUCT_CORE (str);
  GuppiStructField *p;

  p = (GuppiStructField *) g_hash_table_lookup (core->fields, field);
  if (p == NULL)
    return FALSE;

  if (p->type && !gtk_type_is_a (GTK_OBJECT_TYPE (data), p->type))
    return FALSE;

  guppi_refcounting_assign (p->data, data);

  return TRUE;
}

static void
v_struct_foreach (GuppiStruct *str, GuppiStructFn fn, gpointer user_data)
{
  GuppiStructCore *core = GUPPI_STRUCT_CORE (str);
  GList *iter = core->field_names;
  GuppiData *d;

  /* By doing this rather than using the g_hash_table_foreach function,
     we can make sure that our function gets called in the same order
     as the objects have been added to the struct. */

  while (iter) {
    d = v_struct_get (str, (gchar *)iter->data);
    fn ((gchar *)iter->data, d, user_data);
    iter = g_list_next (iter);
  }
}

/***************************************************************************/

static void
guppi_struct_core_class_init (GuppiStructCoreClass *klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *) klass;
  GuppiDataClass *data_class = GUPPI_DATA_CLASS (klass);
  GuppiStructClass *struct_class = GUPPI_STRUCT_CLASS (klass);

  parent_class = gtk_type_class (GUPPI_TYPE_STRUCT);

  object_class->destroy = guppi_struct_core_destroy;
  object_class->finalize = guppi_struct_core_finalize;

  struct_class->add_field = v_struct_add_field;
  struct_class->field_type = v_struct_field_type;
  struct_class->get = v_struct_get;
  struct_class->set = v_struct_set;
  struct_class->foreach = v_struct_foreach;

  data_class->is_leaf_type = TRUE;
}

static void
guppi_struct_core_init (GuppiStructCore *obj)
{
  obj->fields = g_hash_table_new (g_str_hash, g_str_equal);
}

GtkType guppi_struct_core_get_type (void)
{
  static GtkType guppi_struct_core_type = 0;
  if (!guppi_struct_core_type) {
    static const GtkTypeInfo guppi_struct_core_info = {
      "GuppiStructCore",
      sizeof (GuppiStructCore),
      sizeof (GuppiStructCoreClass),
      (GtkClassInitFunc) guppi_struct_core_class_init,
      (GtkObjectInitFunc) guppi_struct_core_init,
      NULL, NULL, (GtkClassInitFunc) NULL
    };
    guppi_struct_core_type =
      gtk_type_unique (GUPPI_TYPE_STRUCT, &guppi_struct_core_info);
  }
  return guppi_struct_core_type;
}

/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */

GuppiStruct *
guppi_struct_core_new (void)
{
  return GUPPI_STRUCT (guppi_type_new (guppi_struct_core_get_type ()));
}

/* $Id: guppi-struct-core.c,v 1.1 2002/01/08 06:29:00 trow Exp $ */


syntax highlighted by Code2HTML, v. 0.9.1