/* This is -*- C -*- */
/* $Id: guppi-seq-boolean.c,v 1.26 2002/01/14 05:01:17 trow Exp $ */

/*
 * guppi-seq-boolean.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-boolean.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>

static GtkObjectClass *parent_class = NULL;

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


static xmlNodePtr
export_xml_element (GuppiSeq *seq, gint i, GuppiXMLDocument *doc)
{
  gboolean x = guppi_seq_boolean_get (GUPPI_SEQ_BOOLEAN (seq), i);
  return xmlNewNode (doc->ns, x ? "true" : "false");
}

static gboolean
import_xml_element (GuppiSeq *seq, GuppiXMLDocument *doc, xmlNodePtr node)
{
  if (!strcmp (node->name, "true"))
    guppi_seq_boolean_append ((GuppiSeqBoolean *) seq, TRUE);
  else if (!strcmp (node->name, "false"))
    guppi_seq_boolean_append ((GuppiSeqBoolean *) seq, FALSE);
  else {
    g_warning ("Bad boolean node: \"%s\"", node->name);
    return FALSE;
  }

  return TRUE;
}

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

typedef struct _GuppiDataOp_Boolean GuppiDataOp_Boolean;
struct _GuppiDataOp_Boolean {
  GuppiDataOp op;

  gint i;
  gsize N;
  gboolean x;

  const gint *iptr;
  const GuppiSeqBoolean *other;
};

static void
op_set (GuppiData *d, GuppiDataOp *op)
{
  GuppiDataOp_Boolean *bop = (GuppiDataOp_Boolean *) op;
  GuppiSeqBoolean *seq;
  GuppiSeqBooleanClass *klass;

  seq = GUPPI_SEQ_BOOLEAN (d);
  klass = GUPPI_SEQ_BOOLEAN_CLASS (GTK_OBJECT (d)->klass);

  g_assert (klass->set);
  klass->set (seq, bop->i, bop->x);
}

static void
op_set_all (GuppiData *d, GuppiDataOp *op)
{
  GuppiDataOp_Boolean *bop = (GuppiDataOp_Boolean *) op;
  GuppiSeqBoolean *seq;
  GuppiSeqBooleanClass *klass;

  seq = GUPPI_SEQ_BOOLEAN (d);
  klass = GUPPI_SEQ_BOOLEAN_CLASS (GTK_OBJECT (d)->klass);

  g_assert (klass->set_all);
  klass->set_all (seq, bop->x);
}

static void
op_set_many (GuppiData *d, GuppiDataOp *op)
{
  GuppiDataOp_Boolean *bop = (GuppiDataOp_Boolean *) op;
  GuppiSeqBoolean *seq;
  GuppiSeqBooleanClass *klass;

  seq = GUPPI_SEQ_BOOLEAN (d);
  klass = GUPPI_SEQ_BOOLEAN_CLASS (GTK_OBJECT (d)->klass);

  if (klass->set_many) {
    klass->set_many (seq, bop->iptr, bop->N, bop->x);
  } else {
    gint i = 0, i0, i1;
    guppi_seq_bounds (GUPPI_SEQ (d), &i0, &i1);
    g_assert (klass->set);
    for (i = 0; i < bop->N; ++i) {
      gint j = bop->iptr[i];
      if (i0 <= j && j <= i1)
	klass->set (seq, j, bop->x);
    }
  }

  /* FIXME missing values! */
}

static void
op_insert (GuppiData *d, GuppiDataOp *op)
{
  GuppiDataOp_Boolean *bop = (GuppiDataOp_Boolean *) op;
  GuppiSeqBoolean *seq;
  GuppiSeqBooleanClass *klass;

  seq = GUPPI_SEQ_BOOLEAN (d);
  klass = GUPPI_SEQ_BOOLEAN_CLASS (GTK_OBJECT (d)->klass);

  if (klass->insert)
    klass->insert (seq, bop->i, bop->x);
  else if (klass->insert_many)
    klass->insert_many (seq, bop->i, bop->x, 1);
  else
    g_assert_not_reached ();
}

static void
op_insert_many (GuppiData *d, GuppiDataOp *op)
{
  GuppiDataOp_Boolean *bop = (GuppiDataOp_Boolean *) op;
  GuppiSeqBoolean *seq;
  GuppiSeqBooleanClass *klass;

  seq = GUPPI_SEQ_BOOLEAN (d);
  klass = GUPPI_SEQ_BOOLEAN_CLASS (GTK_OBJECT (d)->klass);

  g_assert (klass->insert_many);
  klass->insert_many (seq, bop->i, bop->x, bop->N);
}

static void
op_and (GuppiData *d, GuppiDataOp *op)
{
  GuppiDataOp_Boolean *bop = (GuppiDataOp_Boolean *) op;
  GuppiSeqBoolean *seq;
  GuppiSeqBoolean *other_seq;
  GuppiSeqBooleanClass *klass;

  seq = GUPPI_SEQ_BOOLEAN (d);
  klass = GUPPI_SEQ_BOOLEAN_CLASS (GTK_OBJECT (d)->klass);
  other_seq = GUPPI_SEQ_BOOLEAN (bop->other);

  g_assert (klass->bitwise_and);
  klass->bitwise_and (seq, other_seq);
}

static void
op_or (GuppiData *d, GuppiDataOp *op)
{
  GuppiDataOp_Boolean *bop = (GuppiDataOp_Boolean *) op;
  GuppiSeqBoolean *seq;
  GuppiSeqBoolean *other_seq;
  GuppiSeqBooleanClass *klass;

  seq = GUPPI_SEQ_BOOLEAN (d);
  klass = GUPPI_SEQ_BOOLEAN_CLASS (GTK_OBJECT (d)->klass);
  other_seq = GUPPI_SEQ_BOOLEAN (bop->other);

  g_assert (klass->bitwise_or);
  klass->bitwise_or (seq, other_seq);
}

static void
op_xor (GuppiData *d, GuppiDataOp *op)
{
  GuppiDataOp_Boolean *bop = (GuppiDataOp_Boolean *) op;
  GuppiSeqBoolean *seq;
  GuppiSeqBoolean *other_seq;
  GuppiSeqBooleanClass *klass;

  seq = GUPPI_SEQ_BOOLEAN (d);
  klass = GUPPI_SEQ_BOOLEAN_CLASS (GTK_OBJECT (d)->klass);
  other_seq = GUPPI_SEQ_BOOLEAN (bop->other);

  g_assert (klass->bitwise_xor);
  klass->bitwise_xor (seq, other_seq);
}

static void
op_not (GuppiData *d, GuppiDataOp *op)
{
  GuppiSeqBoolean *seq;
  GuppiSeqBooleanClass *klass;

  seq = GUPPI_SEQ_BOOLEAN (d);
  klass = GUPPI_SEQ_BOOLEAN_CLASS (GTK_OBJECT (d)->klass);

  g_assert (klass->bitwise_not);
  klass->bitwise_not (seq);
}

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

/* Default implementations, mostly to deal with missing values. */

static void
v_set (GuppiSeqBoolean *sb, gint i, gboolean x)
{
  GUPPI_SEQ_CLASS (GTK_OBJECT (sb)->klass)->set_missing (GUPPI_SEQ (sb), i, FALSE);
}

static void
v_set_all (GuppiSeqBoolean *sb, gboolean x)
{
  GUPPI_SEQ_CLASS (GTK_OBJECT (sb)->klass)->set_all_missing (GUPPI_SEQ (sb), FALSE);
}

static void
v_set_many (GuppiSeqBoolean *sb, const gint *indices, gsize N, gboolean x)
{
  GuppiSeqClass *seq_class = GUPPI_SEQ_CLASS (GTK_OBJECT (sb)->klass);
  GuppiSeq *seq = GUPPI_SEQ (sb);
  gint i;
  
  

  /* This is a candidate for obvious optimization */
  for (i = 0; i < (gint) N; ++i) {
    seq_class->set_missing (seq, indices[i], FALSE);
  }
}

static void
v_insert (GuppiSeqBoolean *sb, gint i, gboolean x)
{
  GUPPI_SEQ_CLASS (GTK_OBJECT (sb)->klass)->insert_missing (GUPPI_SEQ (sb), i, FALSE, 1);
}

static void
v_insert_many (GuppiSeqBoolean *sb, gint i, gboolean x, gsize N)
{
  GUPPI_SEQ_CLASS (GTK_OBJECT (sb)->klass)->insert_missing (GUPPI_SEQ (sb), i, FALSE, N);
}

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

#if 0
/**
 * guppi_seq_boolean_new_aligned
 * @seq: A sequence
 *
 * Allocates a new boolean sequence whose index bounds are the same as @seq.
 * All the elements of the new sequence are initially set to %FALSE.
 * A default implementation is used.
 *
 * Returns: The newly-allocated sequence
 */
GuppiData *
guppi_seq_boolean_new_aligned (const GuppiSeq *seq)
{
  GuppiSeqBoolean *aligned;

  if (seq == NULL)
    return NULL;

  aligned = GUPPI_SEQ_BOOLEAN (guppi_seq_boolean_new ());

  guppi_seq_boolean_append_many (aligned, FALSE, guppi_seq_size (seq));
  guppi_seq_set_min_index (GUPPI_SEQ (aligned), guppi_seq_min_index (seq));

  return GUPPI_DATA (aligned);
}
#endif

/**
 * guppi_seq_boolean_get
 * @seq: A boolean sequence
 * @i: A position index
 *
 * Returns: The boolean value of the @i-th element of @seq.
 * @i must lie within @seq's bounds.
 */
gboolean
guppi_seq_boolean_get (const GuppiSeqBoolean *seq, gint i)
{
  GuppiSeqBooleanClass *klass;

  g_return_val_if_fail (seq != NULL, FALSE);
  g_return_val_if_fail (guppi_seq_in_bounds (GUPPI_SEQ (seq), i), FALSE);

  klass = GUPPI_SEQ_BOOLEAN_CLASS (GTK_OBJECT (seq)->klass);

  g_assert (klass->get);
  return klass->get ((GuppiSeqBoolean *) seq, i);
}

/**
 * guppi_seq_boolean_set
 * @seq: A boolean sequence
 * @i: A position impl
 * @x: A boolean value
 *
 * Sets the @i-th element of the sequence @seq to @x.
 * @seq must be writeable, and @i must lie within @seq's bounds.
 */
void
guppi_seq_boolean_set (GuppiSeqBoolean *seq, gint i, gboolean x)
{
  g_return_if_fail (seq != NULL && GUPPI_IS_SEQ_BOOLEAN (seq));
  g_return_if_fail (guppi_data_can_change (GUPPI_DATA (seq)));
  g_return_if_fail (guppi_seq_in_bounds (GUPPI_SEQ (seq), i));

  if (guppi_seq_boolean_get (seq, i) != x) {
    GuppiDataOp_Boolean op;
    op.op.op = op_set;
    op.i = i;
    op.x = x;
    guppi_seq_changed_set (GUPPI_SEQ (seq), i, i, (GuppiDataOp *) & op);
  }
}

/**
 * guppi_seq_boolean_set_all
 * @seq: A boolean sequence
 * @x: A boolean value
 *
 * Sets all of the elements of @seq to @x.
 */
void
guppi_seq_boolean_set_all (GuppiSeqBoolean *seq, gboolean x)
{
  GuppiDataOp_Boolean op;
  gint i0, i1;

  g_return_if_fail (seq != NULL && GUPPI_IS_SEQ_BOOLEAN (seq));
  g_return_if_fail (guppi_data_can_change (GUPPI_DATA (seq)));

  guppi_seq_bounds (GUPPI_SEQ (seq), &i0, &i1);
  op.op.op = op_set_all;
  op.x = x;

  guppi_seq_changed_set (GUPPI_SEQ (seq), i0, i1, (GuppiDataOp *) & op);
}

/**
 * guppi_seq_boolean_set_many
 * @seq: A boolean sequence
 * @indices: An array of position indices
 * @N: The length of array @indices
 * @x: A boolean value
 *
 * Iterates across the array @indices, reading the position indices
 * contained in that array and setting the corresponding entries of
 * @seq equal to @x.
 */
void
guppi_seq_boolean_set_many (GuppiSeqBoolean *seq,
			    gint *indices, gsize N, gboolean x)
{
  GuppiDataOp_Boolean op;
  gint i, i0, i1;

  g_return_if_fail (seq != NULL && GUPPI_IS_SEQ_BOOLEAN (seq));
  g_return_if_fail (guppi_data_can_change (GUPPI_DATA (seq)));

  if (N == 0)
    return;

  g_return_if_fail (indices != NULL);

  i0 = i1 = indices[0];
  for (i = 1; i < N; ++i) {
    if (indices[i] < i0)
      i0 = indices[i];
    if (indices[i] > i1)
      i1 = indices[i];
  }

  op.op.op = op_set_many;
  op.iptr = indices;
  op.N = N;
  op.x = x;

  guppi_seq_changed_set (GUPPI_SEQ (seq), i0, i1, (GuppiDataOp *) & op);
}

/**
 * guppi_seq_boolean_clear
 * @seq: A boolean sequence
 *
 * Set all of the elements of @seq equal to %FALSE.
 */
void
guppi_seq_boolean_clear (GuppiSeqBoolean *seq)
{
  guppi_seq_boolean_set_all (seq, FALSE);
}

/**
 * guppi_seq_boolean_prepend
 * @seq: A boolean sequence
 * @x: A boolean value
 *
 * Prepend the boolean value @x to the sequence @seq.
 * @seq must be writeable.
 */
void
guppi_seq_boolean_prepend (GuppiSeqBoolean *seq, gboolean x)
{
  gint i;

  g_return_if_fail (seq != NULL);
  g_return_if_fail (guppi_data_can_change (GUPPI_DATA (seq)));

  i = guppi_seq_min_index (GUPPI_SEQ (seq));
  guppi_seq_boolean_insert (seq, i, x);
}

/**
 * guppi_seq_boolean_prepend_many
 * @seq: A boolean sequence
 * @x: A boolean value
 * @N: A count
 *
 * Prepend @N instances of the boolean value @x to the sequence @seq.
 * @seq must be writeable.
 */
void
guppi_seq_boolean_prepend_many (GuppiSeqBoolean *seq, gboolean x, gsize N)
{
  gint i;

  g_return_if_fail (seq != NULL);
  g_return_if_fail (guppi_data_can_change (GUPPI_DATA (seq)));

  if (N == 0)
    return;

  i = guppi_seq_min_index (GUPPI_SEQ (seq));

  guppi_seq_boolean_insert_many (seq, i, x, N);
}

/**
 * guppi_seq_boolean_append
 * @seq: A boolean sequence
 * @x: A boolean value
 *
 * Append the boolean value @x to the sequence @seq.
 * @seq must be writeable.
 */
void
guppi_seq_boolean_append (GuppiSeqBoolean *seq, gboolean x)
{
  gint i;

  g_return_if_fail (seq != NULL);
  g_return_if_fail (guppi_data_can_change (GUPPI_DATA (seq)));

  i = guppi_seq_max_index (GUPPI_SEQ (seq));
  guppi_seq_boolean_insert (seq, i + 1, x);
}

/**
 * guppi_seq_boolean_append_many
 * @seq: A boolean sequence
 * @x: A boolean value
 * @N: A count
 *
 * Append @N instances of the boolean value @x to the sequence @seq.
 * @seq must be writeable.
 */
void
guppi_seq_boolean_append_many (GuppiSeqBoolean *seq, gboolean x, gsize N)
{
  gint i;

  g_return_if_fail (seq != NULL);
  g_return_if_fail (guppi_data_can_change (GUPPI_DATA (seq)));

  if (N == 0)
    return;

  i = guppi_seq_max_index (GUPPI_SEQ (seq));
  guppi_seq_boolean_insert_many (seq, i + 1, x, N);
}

/**
 * guppi_seq_boolean_insert
 * @seq: A boolean sequence
 * @i: A position index
 * @x: A boolean value
 *
 * Insert the boolean value @x into the sequence @seq at position @i.
 * @seq must be writeable.
 */
void
guppi_seq_boolean_insert (GuppiSeqBoolean *seq, gint i, gboolean x)
{
  GuppiDataOp_Boolean op;

  g_return_if_fail (seq != NULL && GUPPI_IS_SEQ_BOOLEAN (seq));
  g_return_if_fail (guppi_data_can_change (GUPPI_DATA (seq)));

  op.op.op = op_insert;
  op.i = i;
  op.x = x;

  guppi_seq_changed_insert (GUPPI_SEQ (seq), i, i, (GuppiDataOp *) & op);
}

/**
 * guppi_seq_boolean_insert_many
 * @seq: A boolean sequence
 * @i: A position index
 * @x: A boolean value
 * @N: A count
 *
 * Insert @N instances of the boolean value @x into the sequence @seq
 * at position @i.
 * @seq must be writeable.
 */
void
guppi_seq_boolean_insert_many (GuppiSeqBoolean *seq, gint i, gboolean x,
			       gsize N)
{
  GuppiDataOp_Boolean op;

  g_return_if_fail (seq != NULL && GUPPI_IS_SEQ_BOOLEAN (seq));
  g_return_if_fail (guppi_data_can_change (GUPPI_DATA (seq)));

  if (N == 0)
    return;

  op.op.op = op_insert_many;
  op.i = i;
  op.x = x;
  op.N = N;

  guppi_seq_changed_insert (GUPPI_SEQ (seq), i, N, (GuppiDataOp *) & op);
}

/**
 * guppi_seq_boolean_bitwise_and
 * @seq: A boolean sequence
 * @other: Another boolean sequence
 *
 * Set each element of @seq equal to the logical AND of that
 * element and the corresponding element in @other.
 * Only the section of @seq whose indices overlap those of @other
 * are affected.
 * @seq must be writeable.
 */
void
guppi_seq_boolean_bitwise_and (GuppiSeqBoolean *seq,
			       const GuppiSeqBoolean *other)
{
  GuppiDataOp_Boolean op;
  gint i0, i1;

  g_return_if_fail (seq != NULL && GUPPI_IS_SEQ_BOOLEAN (seq));
  g_return_if_fail (guppi_data_can_change (GUPPI_DATA (seq)));

  guppi_seq_common_bounds (GUPPI_SEQ (seq), GUPPI_SEQ (other), &i0, &i1);

  op.op.op = op_and;
  op.other = other;

  guppi_seq_changed_set (GUPPI_SEQ (seq), i0, i1, (GuppiDataOp *) & op);
}

/**
 * guppi_seq_boolean_bitwise_or
 * @seq: A boolean sequence
 * @other: Another boolean sequence
 *
 * Set each element of @seq equal to the logical %OR of that
 * element and the corresponding element in @other.
 * Only the section of @seq whose indices overlap those of @other
 * are affected.
 * @seq must be writeable.
 */
void
guppi_seq_boolean_bitwise_or (GuppiSeqBoolean *seq,
			      const GuppiSeqBoolean *other)
{
  GuppiDataOp_Boolean op;
  gint i0, i1;

  g_return_if_fail (seq != NULL && GUPPI_IS_SEQ_BOOLEAN (seq));
  g_return_if_fail (guppi_data_can_change (GUPPI_DATA (seq)));

  guppi_seq_common_bounds (GUPPI_SEQ (seq), GUPPI_SEQ (other), &i0, &i1);

  op.op.op = op_or;
  op.other = other;

  guppi_seq_changed_set (GUPPI_SEQ (seq), i0, i1, (GuppiDataOp *) & op);
}

/**
 * guppi_seq_boolean_bitwise_xor
 * @seq: A boolean sequence
 * @other: Another boolean sequence
 *
 * Set each element of @seq equal to the logical %XOR of that
 * element and the corresponding element in @other.
 * Only the section of @seq whose indices overlap those of @other
 * are affected.
 * @seq must be writeable.
 */
void
guppi_seq_boolean_bitwise_xor (GuppiSeqBoolean *seq,
			       const GuppiSeqBoolean *other)
{
  GuppiDataOp_Boolean op;
  gint i0, i1;

  g_return_if_fail (seq != NULL && GUPPI_IS_SEQ_BOOLEAN (seq));
  g_return_if_fail (guppi_data_can_change (GUPPI_DATA (seq)));

  guppi_seq_common_bounds (GUPPI_SEQ (seq), GUPPI_SEQ (other), &i0, &i1);

  op.op.op = op_xor;
  op.other = other;

  guppi_seq_changed_set (GUPPI_SEQ (seq), i0, i1, (GuppiDataOp *) & op);
}

/**
 * guppi_seq_boolean_bitwise_not
 * @seq: A boolean sequence
 *
 * Set each element of @seq equal to the logical %NOT of that
 * element.
 * @seq must be writeable.
 */
void
guppi_seq_boolean_bitwise_not (GuppiSeqBoolean *seq)
{
  GuppiDataOp_Boolean op;
  gint i0, i1;

  g_return_if_fail (seq != NULL && GUPPI_IS_SEQ_BOOLEAN (seq));
  g_return_if_fail (guppi_data_can_change (GUPPI_DATA (seq)));

  guppi_seq_bounds (GUPPI_SEQ (seq), &i0, &i1);

  op.op.op = op_not;

  guppi_seq_changed_set (GUPPI_SEQ (seq), i0, i1, (GuppiDataOp *) & op);
}

/**
 * guppi_seq_boolean_first_true
 * @seq: A boolean sequence
 *
 * Finds the first %TRUE element of @seq.  If @seq contains only
 * %FALSE values, an out-of-bounds index is returned.
 *
 * Returns: The index of the lowest-numbered position in @seq
 * whose value is %TRUE.
 */
gint
guppi_seq_boolean_first_true (const GuppiSeqBoolean *seq)
{
  GuppiSeqBooleanClass *klass;
  gint i, i0, i1;

  g_return_val_if_fail (seq != NULL, 1);

  klass = GUPPI_SEQ_BOOLEAN_CLASS (GTK_OBJECT (seq)->klass);

  i0 = guppi_seq_min_index (GUPPI_SEQ (seq));

  if (klass->next_true) {
    return klass->next_true ((GuppiSeqBoolean *) seq, i0 - 1);
  }

  g_assert (klass->get);
  i1 = guppi_seq_max_index (GUPPI_SEQ (seq));
  for (i = i0; i <= i1 && klass->get ((GuppiSeqBoolean *) seq, i); ++i);
  return i;
}

/**
 * guppi_seq_boolean_next_true
 * @seq: A boolean sequence
 * @i: A position index
 *
 * Finds the first %TRUE element of @seq whose index is greater
 * that @i.  If no such element exists, an out-of-bounds index
 * value is returned.
 *
 * Returns: The index of the next %TRUE value in @seq.
 */
gint
guppi_seq_boolean_next_true (const GuppiSeqBoolean *seq, gint i)
{
  GuppiSeqBooleanClass *klass;
  gint i1;

  g_return_val_if_fail (seq != NULL, 1);

  klass = GUPPI_SEQ_BOOLEAN_CLASS (GTK_OBJECT (seq)->klass);

  i1 = guppi_seq_max_index (GUPPI_SEQ (seq));
  if (i1 < i)
    return i;

  if (klass->next_true) {
    return klass->next_true ((GuppiSeqBoolean *) seq, i);
  }

  g_assert (klass->get);

  while (i < i1) {
    ++i;
    if (klass->get ((GuppiSeqBoolean *) seq, i))
      return i;
  }
  return i;
}

/**
 * guppi_seq_boolean_first_jointly_true
 * @a: A boolean sequence
 * @b: Another boolean sequence
 *
 * Finds the lowest-valued index value which is common to
 * both @a and @b, and for which both sequences contain %TRUE.
 * If no such element exists, an out-of-bounds index is
 * returned.
 *
 * Returns: The index of the lowest-numbered position
 * whose value is %TRUE for both @a and @b.
 */
gint
guppi_seq_boolean_first_jointly_true (const GuppiSeqBoolean *a,
				      const GuppiSeqBoolean *b)
{
  gint i, i0, i1;

  g_return_val_if_fail (GUPPI_IS_SEQ_BOOLEAN (a), 0);
  g_return_val_if_fail (GUPPI_IS_SEQ_BOOLEAN (b), 0);

  guppi_seq_common_bounds (GUPPI_SEQ (a), GUPPI_SEQ (b), &i0, &i1);

  i = i0;
  if (!guppi_seq_boolean_get (a, i))
    i = guppi_seq_boolean_next_true (a, i);

  while (i <= i1 && !guppi_seq_boolean_get (b, i))
    i = guppi_seq_boolean_next_true (a, i);

  return i;
}

/**
 * guppi_seq_boolean_next_jointly_true
 * @a: A boolean sequences
 * @b: Another boolean sequences
 * @i: A position index
 * 
 * Finds the index value of the next element beyond index @i which is
 * %TRUE for both @a and @b.  If no such element exists, an out-of-bounds
 * value is returned.
 *
 * Returns: The next index value that is %TRUE for both @a and @b.
 */
gint
guppi_seq_boolean_next_jointly_true (const GuppiSeqBoolean *a,
				     const GuppiSeqBoolean *b, gint i)
{
  gint i0, i1;
  gint ia, ib;

  g_return_val_if_fail (GUPPI_IS_SEQ_BOOLEAN (a), 0);
  g_return_val_if_fail (GUPPI_IS_SEQ_BOOLEAN (b), 0);

  guppi_seq_common_bounds (GUPPI_SEQ (a), GUPPI_SEQ (b), &i0, &i1);

  while (i <= i1) {
    ia = guppi_seq_boolean_next_true (a, i);
    ib = guppi_seq_boolean_next_true (b, i);

    if (ia <= i1 && ib <= i1) {
      if (ia == ib)
	return ia;
      else if (ia < ib && guppi_seq_boolean_get (a, ib))
	return ib;
      else if (ia > ib && guppi_seq_boolean_get (b, ia))
	return ia;
    }

    i = MAX (ia, ib);
  }

  return i;
}

/**
 * guppi_seq_boolean_true_count
 * @seq: A boolean sequences
 *
 * Returns: The number of elements of the sequence @seq
 * that are equal to %TRUE.
 */
gsize
guppi_seq_boolean_true_count (const GuppiSeqBoolean *seq)
{
  GuppiSeqBooleanClass *klass;
  gint i, i0, i1;
  gsize count = 0;

  g_return_val_if_fail (seq != NULL, 0);

  klass = GUPPI_SEQ_BOOLEAN_CLASS (GTK_OBJECT (seq)->klass);

  if (klass->true_count) {
    return klass->true_count ((GuppiSeqBoolean *) seq);
  }

  g_assert (klass->get);

  guppi_seq_indices (GUPPI_SEQ (seq), &i0, &i1);

  for (i = i0; i <= i1; ++i) {
    if (klass->get ((GuppiSeqBoolean *) seq, i))
      ++count;
  }

  return count;
}

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

static void
guppi_seq_boolean_class_init (GuppiSeqBooleanClass *klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *) klass;
  GuppiSeqClass *seq_class = GUPPI_SEQ_CLASS (klass);

  parent_class = gtk_type_class (GUPPI_TYPE_SEQ);

  klass->set = v_set;
  klass->set_all = v_set_all;
  klass->set_many = v_set_many;
  klass->insert = v_insert;
  klass->insert_many = v_insert_many;

  seq_class->export_xml_element = export_xml_element;
  seq_class->import_xml_element = import_xml_element;

  object_class->finalize = guppi_seq_boolean_finalize;
}

static void
guppi_seq_boolean_init (GuppiSeqBoolean * obj)
{

}

GtkType guppi_seq_boolean_get_type (void)
{
  static GtkType guppi_seq_boolean_type = 0;
  if (!guppi_seq_boolean_type) {
    static const GtkTypeInfo guppi_seq_boolean_info = {
      "GuppiSeqBoolean",
      sizeof (GuppiSeqBoolean),
      sizeof (GuppiSeqBooleanClass),
      (GtkClassInitFunc) guppi_seq_boolean_class_init,
      (GtkObjectInitFunc) guppi_seq_boolean_init,
      NULL, NULL, (GtkClassInitFunc) NULL
    };
    guppi_seq_boolean_type =
      gtk_type_unique (GUPPI_TYPE_SEQ, &guppi_seq_boolean_info);
  }
  return guppi_seq_boolean_type;
}

/* $Id: guppi-seq-boolean.c,v 1.26 2002/01/14 05:01:17 trow Exp $ */


syntax highlighted by Code2HTML, v. 0.9.1