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

/*
 * guppi-seq-scalar-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-scalar-core.h"

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

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

static GtkObjectClass *parent_class = NULL;

static void
guppi_seq_scalar_core_finalize (GtkObject *obj)
{
  GuppiSeqScalarCore *core = GUPPI_SEQ_SCALAR_CORE (obj);

  guppi_unref0 (core->garray);

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

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

#if 0
static void
changed_bounds (GuppiSeqScalarCore *impl)
{
  GuppiAttributeBag *bag = GUPPI_DATA (impl)->attribute_bag;
  gint i0, i1;

  i0 = impl->index_basis;
  i1 = impl->index_basis - 1 + impl->size;

  guppi_attribute_bag_set (bag, "min_index", i0);
  guppi_attribute_bag_set (bag, "max_index", i1);
}
#endif

static double
v_seq_scalar_get (GuppiSeqScalar *ss, gint i)
{
  GuppiSeqScalarCore *core = GUPPI_SEQ_SCALAR_CORE (ss);
  const double *data;

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

static void
v_seq_scalar_set (GuppiSeqScalar *ss, gint i, double x)
{
  GuppiSeqScalarCore *core = GUPPI_SEQ_SCALAR_CORE (ss);
  double *data;

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

  data[i] = x;

  if (GUPPI_SEQ_SCALAR_CLASS (parent_class)->set)
    GUPPI_SEQ_SCALAR_CLASS (parent_class)->set (ss, i, x);
}

static void
v_seq_scalar_set_many (GuppiSeqScalar *ss, gint i,
		       const double *ptr, gint stride, gsize N)
{
  GuppiSeqScalarCore *core = GUPPI_SEQ_SCALAR_CORE (ss);

  double *data;
  const guchar *byte_ptr;
  gint j;

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

  i -= core->index_basis;

  if (guppi_garray_size (core->garray) < (i + N - 1))
    guppi_garray_set_size (core->garray, i + N - 1);

  data = (double *) guppi_garray_data (core->garray);

  byte_ptr = (const guchar *) ptr;
  for (j = 0; j < N; ++j) {
    double x = *(const double *) byte_ptr;
    data[i + j] = x;
    byte_ptr += stride;
  }

  if (GUPPI_SEQ_SCALAR_CLASS (parent_class)->set_many) {
    i += core->index_basis;
    GUPPI_SEQ_SCALAR_CLASS (parent_class)->set_many (ss, i, ptr, stride, N);
  }

}

static void
v_seq_scalar_insert (GuppiSeqScalar *ss, gint i, double x)
{
  GuppiSeqScalarCore *core = GUPPI_SEQ_SCALAR_CORE (ss);
  double *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 = (double *) guppi_garray_data (core->garray);
  for (j = core->size - 1; i <= j; --j)
    data[j + 1] = data[j];
  data[i] = x;
  ++core->size;

  if (GUPPI_SEQ_SCALAR_CLASS (parent_class)->insert) {
    i += core->index_basis;
    GUPPI_SEQ_SCALAR_CLASS (parent_class)->insert (ss, i, x);
  }
}

static void
v_seq_scalar_insert_many (GuppiSeqScalar *ss, gint i,
			  const double *ptr, gint stride, gsize N)
{
  GuppiSeqScalarCore *core = GUPPI_SEQ_SCALAR_CORE (ss);
  double *data;
  const guchar *byte_ptr;
  gint j;

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

  i -= core->index_basis;

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

  data = (double *) guppi_garray_data (core->garray);

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

  byte_ptr = (const guchar *) ptr;
  for (j = 0; j < N; ++j) {
    double x = *(const double *) byte_ptr;
    data[i + j] = x;
    byte_ptr += stride;
  }

  i += core->index_basis;
  core->size += N;

  if (GUPPI_SEQ_SCALAR_CLASS (parent_class)->insert) {
    GUPPI_SEQ_SCALAR_CLASS (parent_class)->insert_many (ss, i, ptr, stride, N);
  }
}

static double *
v_seq_scalar_raw (GuppiSeqScalar *impl, gint *stride)
{
  GuppiSeqScalarCore *core = GUPPI_SEQ_SCALAR_CORE (impl);
  gint8 *p;

  p = (gint8 *) guppi_garray_data (core->garray);
  p -= sizeof (double) * core->index_basis;
  *stride = sizeof (double);

  return (double *) p;
}

static void
v_seq_size_hint (GuppiSeq *seq, gsize n)
{
  GuppiSeqScalarCore *core = GUPPI_SEQ_SCALAR_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 GuppiSeqScalarCore *core = GUPPI_SEQ_SCALAR_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)
{
  GuppiSeqScalarCore *core = GUPPI_SEQ_SCALAR_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)
{
  GuppiSeqScalarCore *core = GUPPI_SEQ_SCALAR_CORE (seq);
  double *data;
  gint j;

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

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

  core->size -= N;

  if (GUPPI_SEQ_CLASS (parent_class)->delete_many)
    GUPPI_SEQ_CLASS (parent_class)->delete_many (seq, i, N);
}

static void
v_seq_insert_generic (GuppiSeq *seq, gint i, gsize N)
{
  double val = 0;
  v_seq_scalar_insert_many (GUPPI_SEQ_SCALAR (seq), i, &val, 0, N);
}

static GuppiData *
v_data_copy (GuppiData *d)
{
  GuppiSeqScalarCore *core = GUPPI_SEQ_SCALAR_CORE (d);
  GuppiSeqScalarCore *copy;
  gint i;
  double *data;
  double *copy_data;

  copy = GUPPI_SEQ_SCALAR_CORE (guppi_type_new (GUPPI_TYPE_SEQ_SCALAR_CORE));

  copy->index_basis = core->index_basis;
  copy->size = core->size;
  guppi_garray_set_size (copy->garray, copy->size);

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

  if (GUPPI_SEQ_CLASS (GTK_OBJECT (d)->klass)->copy_missing)
    GUPPI_SEQ_CLASS (GTK_OBJECT (d)->klass)->copy_missing (GUPPI_SEQ (copy), GUPPI_SEQ (d));

  return GUPPI_DATA (copy);
}

static gint
v_data_size_in_bytes (GuppiData *d)
{
  GuppiSeqScalarCore *core = GUPPI_SEQ_SCALAR_CORE (d);
  gint sib = guppi_garray_size (core->garray) * sizeof (double) + sizeof (GuppiSeqScalarCore);

  if (GUPPI_DATA_CLASS (d)->get_size_in_bytes)
    sib += GUPPI_DATA_CLASS (d)->get_size_in_bytes (d);

  return sib;
}


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

static void
guppi_seq_scalar_core_class_init (GuppiSeqScalarCoreClass *klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *) klass;
  GuppiDataClass *data_class = GUPPI_DATA_CLASS (klass);
  GuppiSeqClass *seq_class = GUPPI_SEQ_CLASS (klass);
  GuppiSeqScalarClass *seq_scalar_class = GUPPI_SEQ_SCALAR_CLASS (klass);

  parent_class = gtk_type_class (GUPPI_TYPE_SEQ_SCALAR);

  object_class->finalize = guppi_seq_scalar_core_finalize;

  seq_scalar_class->get = v_seq_scalar_get;
  seq_scalar_class->set = v_seq_scalar_set;
  seq_scalar_class->set_many = v_seq_scalar_set_many;
  seq_scalar_class->insert = v_seq_scalar_insert;
  seq_scalar_class->insert_many = v_seq_scalar_insert_many;
  seq_scalar_class->raw_access = v_seq_scalar_raw;

  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->insert_generic = v_seq_insert_generic;
  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_scalar_core_init (GuppiSeqScalarCore *obj)
{
  obj->index_basis = 0;
  obj->size = 0;
  obj->garray = guppi_garray_new (sizeof (double));
}

GtkType guppi_seq_scalar_core_get_type (void)
{
  static GtkType guppi_seq_scalar_core_type = 0;
  if (!guppi_seq_scalar_core_type) {
    static const GtkTypeInfo guppi_seq_scalar_core_info = {
      "GuppiSeqScalarCore",
      sizeof (GuppiSeqScalarCore),
      sizeof (GuppiSeqScalarCoreClass),
      (GtkClassInitFunc) guppi_seq_scalar_core_class_init,
      (GtkObjectInitFunc) guppi_seq_scalar_core_init,
      NULL, NULL, (GtkClassInitFunc) NULL
    };
    guppi_seq_scalar_core_type =
      gtk_type_unique (GUPPI_TYPE_SEQ_SCALAR,
		       &guppi_seq_scalar_core_info);
  }
  return guppi_seq_scalar_core_type;
}

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

GuppiSeqScalar *
guppi_seq_scalar_core_new (void)
{
  return GUPPI_SEQ_SCALAR (guppi_type_new (guppi_seq_scalar_core_get_type ()));
}

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


syntax highlighted by Code2HTML, v. 0.9.1