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

/*
 * guppi-seq-string-core.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-seq-string-core.h"
/* #include <gnome.h> */

#include <string.h>

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

#include <guppi-memory.h>
#include <guppi-data-plug-in.h>


static GtkObjectClass *parent_class = NULL;

static void
guppi_seq_string_core_destroy (GtkObject *obj)
{
  if (parent_class->destroy)
    parent_class->destroy (obj);
}

static void
guppi_seq_string_core_finalize (GtkObject *obj)
{
  GuppiSeqStringCore *core = GUPPI_SEQ_STRING_CORE (obj);
  gchar **data;
  gint i;

  data = (gchar **) guppi_garray_data (core->garray);
  for (i=0; i<core->size; ++i)
    guppi_free (data[i]);

  guppi_unref0 (core->garray);

  if (parent_class->finalize)
    parent_class->finalize (obj);
}

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

static const gchar *
v_seq_string_get (GuppiSeqString *seq, gint i)
{
  const GuppiSeqStringCore *core = GUPPI_SEQ_STRING_CORE (seq);
  gchar **data;

  data = (gchar **) guppi_garray_data (core->garray);
  i -= core->index_basis;
  return data[i];
}

static void
v_seq_string_set (GuppiSeqString *seq, gint i, gchar *str)
{
  GuppiSeqStringCore *core = GUPPI_SEQ_STRING_CORE (seq);
  gchar **data;

  data = (gchar **) guppi_garray_data (core->garray);
  i -= core->index_basis;
  if (data[i])
    guppi_free (data[i]);
  data[i] = str;

  if (GUPPI_SEQ_STRING_CLASS (parent_class)->set) {
    i += core->index_basis;
    GUPPI_SEQ_STRING_CLASS (parent_class)->set (seq, i, str);
  }
}

static void
v_seq_string_insert (GuppiSeqString *seq, gint i, gchar *str)
{
  GuppiSeqStringCore *core = GUPPI_SEQ_STRING_CORE (seq);
  gchar **data;
  gint j;

  if (core->size == 0)
    core->index_basis = i;

  i -= core->index_basis;

  if (guppi_garray_size (core->garray) <= core->size)
    guppi_garray_set_size (core->garray, MAX (20, 2 *core->size));

  data = (gchar **) guppi_garray_data (core->garray);
  for (j = core->size - 1; i <= j; --j)
    data[j + 1] = data[j];
  data[i] = str;
  ++core->size;

  if (GUPPI_SEQ_STRING_CLASS (parent_class)->insert) {
    i += core->index_basis;
    GUPPI_SEQ_STRING_CLASS (parent_class)->insert (seq, i, str);
  }
}

static void
v_seq_size_hint (GuppiSeq *seq, gsize n)
{
  GuppiSeqStringCore *core = GUPPI_SEQ_STRING_CORE (seq);

  if (guppi_garray_size (core->garray) < n)
    guppi_garray_set_size (core->garray, n);

  if (GUPPI_SEQ_CLASS (parent_class)->size_hint)
    GUPPI_SEQ_CLASS (parent_class)->size_hint (seq, n);
}

static void
v_seq_get_bounds (GuppiSeq *seq, gint *min, gint *max)
{
  const GuppiSeqStringCore *core = GUPPI_SEQ_STRING_CORE (seq);

  if (min)
    *min = core->index_basis;

  if (max)
    *max = core->index_basis - 1 + core->size;
}

static void
v_seq_shift_indices (GuppiSeq *seq, gint delta)
{
  GuppiSeqStringCore *core = GUPPI_SEQ_STRING_CORE (seq);
  core->index_basis += delta;
  
  if (GUPPI_SEQ_CLASS (parent_class)->shift_indices)
    GUPPI_SEQ_CLASS (parent_class)->shift_indices (seq, delta);
}

static void
v_seq_delete_many (GuppiSeq *seq, gint i, gsize N)
{
  GuppiSeqStringCore *core = GUPPI_SEQ_STRING_CORE (seq);
  gchar **data;
  gint j;

  data = (gchar **) guppi_garray_data (core->garray);
  i -= core->index_basis;

  for (j = i; j < i + N; ++j) {
    guppi_free (data[j]);
  }

  for (j = i; j + N < core->size; ++j) {
    data[j] = data[j + N];
  }

  core->size -= N;

  if (GUPPI_SEQ_CLASS (parent_class)->delete_many) {
    i += core->index_basis;
    GUPPI_SEQ_CLASS (parent_class)->delete_many (seq, i, N);
  }
}

static GuppiData *
v_data_copy (GuppiData *seq)
{
  GuppiSeqStringCore *core = GUPPI_SEQ_STRING_CORE (seq);
  GuppiSeqStringCore *copy;
  gint i;
  gchar **data;
  gchar **copy_data;

  copy = GUPPI_SEQ_STRING_CORE (guppi_type_new (GUPPI_TYPE_SEQ_STRING_CORE));

  copy->index_basis = core->index_basis;
  copy->size = core->size;
  copy->garray = guppi_garray_new (sizeof (gchar *));
  guppi_garray_set_size (copy->garray, copy->size);

  data = (gchar **) guppi_garray_data (core->garray);
  copy_data = (gchar **) guppi_garray_data (copy->garray);
  for (i = 0; i < core->size; ++i)
    copy_data[i] = guppi_strdup (data[i]);

  return GUPPI_DATA (copy);
}

static gint
v_data_size_in_bytes (GuppiData *seq)
{
  GuppiSeqStringCore *core = GUPPI_SEQ_STRING_CORE (seq);
  gint i, sum = 0;
  gchar **data = (gchar **) guppi_garray_data (core->garray);

  sum += sizeof (GuppiSeqStringCore);
  sum += core->size *sizeof (gchar *);

  for (i = 0; i < core->size; ++i)
    if (data[i])
      sum += 1 + strlen (data[i]);

  if (GUPPI_DATA_CLASS (parent_class)->get_size_in_bytes)
    sum += GUPPI_DATA_CLASS (parent_class)->get_size_in_bytes (seq);

  return sum;
}

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

static void
guppi_seq_string_core_class_init (GuppiSeqStringCoreClass *klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *) klass;
  GuppiDataClass *data_class = GUPPI_DATA_CLASS (klass);
  GuppiSeqClass *seq_class = GUPPI_SEQ_CLASS (klass);
  GuppiSeqStringClass *seq_string_class =
    GUPPI_SEQ_STRING_CLASS (klass);

  parent_class = gtk_type_class (GUPPI_TYPE_SEQ_STRING);

  object_class->destroy = guppi_seq_string_core_destroy;
  object_class->finalize = guppi_seq_string_core_finalize;

  seq_string_class->get = v_seq_string_get;
  seq_string_class->set = v_seq_string_set;
  seq_string_class->insert = v_seq_string_insert;

  seq_class->size_hint = v_seq_size_hint;
  seq_class->get_bounds = v_seq_get_bounds;
  seq_class->shift_indices = v_seq_shift_indices;
  seq_class->delete_many = v_seq_delete_many;
  seq_class->support_missing_values = TRUE;

  data_class->copy = v_data_copy;
  data_class->get_size_in_bytes = v_data_size_in_bytes;
  data_class->is_leaf_type = TRUE;
}

static void
guppi_seq_string_core_init (GuppiSeqStringCore *obj)
{
  obj->index_basis = 0;
  obj->size = 0;
  obj->garray = guppi_garray_new (sizeof (gchar *));
}

GtkType guppi_seq_string_core_get_type (void)
{
  static GtkType guppi_seq_string_core_type = 0;
  if (!guppi_seq_string_core_type) {
    static const GtkTypeInfo guppi_seq_string_core_info = {
      "GuppiSeqStringCore",
      sizeof (GuppiSeqStringCore),
      sizeof (GuppiSeqStringCoreClass),
      (GtkClassInitFunc) guppi_seq_string_core_class_init,
      (GtkObjectInitFunc) guppi_seq_string_core_init,
      NULL, NULL, (GtkClassInitFunc) NULL
    };
    guppi_seq_string_core_type =
      gtk_type_unique (GUPPI_TYPE_SEQ_STRING,
		       &guppi_seq_string_core_info);
  }
  return guppi_seq_string_core_type;
}

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

GuppiSeqString *
guppi_seq_string_core_new (void)
{
  return GUPPI_SEQ_STRING (guppi_type_new (guppi_seq_string_core_get_type ()));
}

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


syntax highlighted by Code2HTML, v. 0.9.1