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

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

#include <stdlib.h>
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>
#include <guppi-convenient.h>
#include <guppi-data-plug-in.h>


static GtkObjectClass *parent_class = NULL;

enum {
  ARG_0
};

static void
guppi_seq_integer_core_get_arg (GtkObject *obj, GtkArg *arg, guint arg_id)
{
  switch (arg_id) {

  default:
    break;
  };
}

static void
guppi_seq_integer_core_set_arg (GtkObject *obj, GtkArg *arg, guint arg_id)
{
  switch (arg_id) {

  default:
    break;
  };
}

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

static void
guppi_seq_integer_core_finalize (GtkObject *obj)
{
  GuppiSeqIntegerCore *core = GUPPI_SEQ_INTEGER_CORE (obj);

  guppi_unref0 (core->garray);

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

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

static void
v_seq_integer_range (GuppiSeqInteger *si, gint *min, gint *max)
{
  GuppiSeqIntegerCore *core = GUPPI_SEQ_INTEGER_CORE (si);
  gint x0 = 0, x1 = 0, i, a;
  const gint *ptr = (const gint *) guppi_garray_data (core->garray);

  if (!core->cached_minmax) {

    if (core->size) {
      x0 = x1 = ptr[0];
      for (i = 1; i < core->size; ++i) {
	a = ptr[i];
	if (a < x0)
	  x0 = a;
	if (a > x1)
	  x1 = a;
      }
    }

    core->min = x0;
    core->max = x1;
    core->cached_minmax = TRUE;
  }

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

  if (max)
    *max = core->max;
}

static gint
v_seq_integer_frequency (GuppiSeqInteger *si, gint k)
{
  GuppiSeqIntegerCore *core = GUPPI_SEQ_INTEGER_CORE (si);
  gint count = 0, i;
  const gint *ptr = (const gint *) guppi_garray_data (core->garray);

  for (i = 0; i < core->size; ++i)
    if (k == ptr[i])
      ++count;

  return count;
}

static gint
v_seq_integer_get (GuppiSeqInteger *si, gint i)
{
  GuppiSeqIntegerCore *core = GUPPI_SEQ_INTEGER_CORE (si);
  const gint *ptr = (const gint *) guppi_garray_data (core->garray);

  return ptr[i - core->index_basis];
}

static void
v_seq_integer_set (GuppiSeqInteger *si, gint i, gint val)
{
  GuppiSeqIntegerCore *core = GUPPI_SEQ_INTEGER_CORE (si);
  gint *ptr = (gint *) guppi_garray_data (core->garray);
  gint old_val;

  i -= core->index_basis;

  old_val = ptr[i];

  if (core->cached_minmax) {

    if (val < core->min)
      core->min = val;

    if (val > core->max)
      core->max = val;

    if ((old_val == core->min && val != core->min) ||
	(old_val == core->max && val != core->max))
      core->cached_minmax = FALSE;
  }

  ptr[i] = val;

  if (GUPPI_SEQ_INTEGER_CLASS (parent_class)->set)
    GUPPI_SEQ_INTEGER_CLASS (parent_class)->set (si, i + core->index_basis, val);
}

static void
v_seq_integer_insert (GuppiSeqInteger *si, gint i, const gint *ptr, gsize N)
{
  GuppiSeqIntegerCore *core = GUPPI_SEQ_INTEGER_CORE (si);
  gint *data;
  gint a, j;

  i -= core->index_basis;

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

  if (core->cached_minmax) {
    for (j = 0; j < N; ++j) {
      a = ptr[j];
      if (a < core->min)
	core->min = a;
      if (a > core->max)
	core->max = a;
    }
  }

  data = (gint *) guppi_garray_data (core->garray);
  for (j = core->size - N; i <= j; --j)
    data[j + N] = data[j];
  for (j = 0; j < N; ++j)
    data[i + j] = ptr[j];
  core->size += N;

  if (GUPPI_SEQ_INTEGER_CLASS (parent_class)->insert)
    GUPPI_SEQ_INTEGER_CLASS (parent_class)->insert (si, i + core->index_basis, ptr, N);
}

static void
v_seq_size_hint (GuppiSeq *seq, gsize N)
{
  GuppiSeqIntegerCore *core = GUPPI_SEQ_INTEGER_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)
{
  GuppiSeqIntegerCore *core = GUPPI_SEQ_INTEGER_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)
{
  GuppiSeqIntegerCore *core = GUPPI_SEQ_INTEGER_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)
{
  GuppiSeqIntegerCore *core = GUPPI_SEQ_INTEGER_CORE (seq);
  gint *data;
  gint j;

  /* This could be optimized. */
  core->cached_minmax = FALSE;

  data = (gint *) 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 + core->index_basis, N);
}

static GuppiData *
v_data_copy (GuppiData *d)
{
  GuppiSeqIntegerCore *core = GUPPI_SEQ_INTEGER_CORE (d);
  GuppiSeqIntegerCore *copy;
  gint i;
  gint *data;
  gint *copy_data;

  copy = GUPPI_SEQ_INTEGER_CORE (guppi_type_new (GUPPI_TYPE_SEQ_INTEGER_CORE));

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

  data = (gint *) guppi_garray_data (core->garray);
  copy_data = (gint *) guppi_garray_data (copy->garray);

  for (i = 0; i < core->size; ++i)
    copy_data[i] = data[i];

  return GUPPI_DATA (copy);
}

static gint
v_data_size_in_bytes (GuppiData *d)
{
  GuppiSeqIntegerCore *core = GUPPI_SEQ_INTEGER_CORE (d);
  gint sz;

  sz =  guppi_garray_size (core->garray) * sizeof (double) + sizeof (GuppiSeqIntegerCore);

  if (GUPPI_DATA_CLASS (parent_class)->get_size_in_bytes)
    sz += GUPPI_DATA_CLASS (parent_class)->get_size_in_bytes (d);

  return sz;
}

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

static void
guppi_seq_integer_core_class_init (GuppiSeqIntegerCoreClass *klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *) klass;
  GuppiDataClass *data_class = GUPPI_DATA_CLASS (klass);
  GuppiSeqClass *seq_class = GUPPI_SEQ_CLASS (klass);
  GuppiSeqIntegerClass *seq_integer_class = GUPPI_SEQ_INTEGER_CLASS (klass);

  parent_class = gtk_type_class (GUPPI_TYPE_SEQ_INTEGER);

  object_class->get_arg = guppi_seq_integer_core_get_arg;
  object_class->set_arg = guppi_seq_integer_core_set_arg;
  object_class->destroy = guppi_seq_integer_core_destroy;
  object_class->finalize = guppi_seq_integer_core_finalize;

  seq_integer_class->range = v_seq_integer_range;
  seq_integer_class->frequency = v_seq_integer_frequency;
  seq_integer_class->get = v_seq_integer_get;
  seq_integer_class->set = v_seq_integer_set;
  seq_integer_class->insert = v_seq_integer_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_integer_core_init (GuppiSeqIntegerCore *obj)
{
  obj->index_basis = 0;
  obj->size = 0;
  obj->garray = guppi_garray_new (sizeof (gint));
}

GtkType guppi_seq_integer_core_get_type (void)
{
  static GtkType guppi_seq_integer_core_type = 0;
  if (!guppi_seq_integer_core_type) {
    static const GtkTypeInfo guppi_seq_integer_core_info = {
      "GuppiSeqIntegerCore",
      sizeof (GuppiSeqIntegerCore),
      sizeof (GuppiSeqIntegerCoreClass),
      (GtkClassInitFunc) guppi_seq_integer_core_class_init,
      (GtkObjectInitFunc) guppi_seq_integer_core_init,
      NULL, NULL, (GtkClassInitFunc) NULL
    };
    guppi_seq_integer_core_type =
      gtk_type_unique (GUPPI_TYPE_SEQ_INTEGER, &guppi_seq_integer_core_info);
  }
  return guppi_seq_integer_core_type;
}

GuppiSeqInteger *
guppi_seq_integer_core_new (void)
{
  return GUPPI_SEQ_INTEGER (guppi_type_new (guppi_seq_integer_core_get_type ()));
}

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


syntax highlighted by Code2HTML, v. 0.9.1