/* This is -*- C -*- */
/* vim: set sw=2: */
/* $Id: datatable1.c,v 1.4 2002/01/14 05:01:25 trow Exp $ */

/*
 * datatable1.c
 *
 * Copyright (C) 2001 The Free Software Foundation, Inc.
 *
 * Developed by Jon Trowbridge <trow@gnu.org>
 */

/*
 * 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 <math.h>
#include <string.h>
#include "guppi-test-framework.h"
#include <guppi-data-table.h>
#include <guppi-useful.h>
#include <guppi-data-init.h>

#define eq(x,y) (fabs((x)-(y))<1e-12*MIN(1+fabs(x),1+fabs(y)))

static gboolean
plugins (gpointer foo)
{
  guppi_plug_in_path_set ("../../plug-ins/data_impl/data_table");
  guppi_plug_in_spec_find_all ();
  return guppi_plug_in_count () > 0;
}

static gboolean
construct (gpointer foo)
{
  GuppiData *d;

  guppi_test_subtest ("Create");
  d = guppi_data_new ("GuppiDataTableCore");
  if (d == NULL)
    return FALSE;

  guppi_test_subtest ("Destroy");
  guppi_unref (d);
  
  return TRUE;
}

static gboolean
sanity_check (GuppiDataTable *tab, gint r, gint c)
{
  gint R, C, i, j;

  guppi_test_subtest ("sanity-checking dimensions");
  guppi_data_table_get_dimensions (tab, &R, &C);

  if (r != R || c != C || R != guppi_data_table_get_row_count (tab) || C != guppi_data_table_get_col_count (tab)) {
    g_print ("have (%d, %d), expected (%d, %d)\n", R, C, r, c);
    return FALSE;
  }

  guppi_test_subtest ("checking initialization to zero");
  for (i = 0; i < R; ++i) {
    for (j = 0; j < C; ++j) {
      if (guppi_data_table_get_entry (tab, i, j) > 1e-16)
	return FALSE;
    }
  }

  guppi_test_subtest ("checking label initialization to null");
  for (i = 0; i < R; ++i) {
    if (guppi_data_table_get_row_label (tab, i) != NULL)
      return FALSE;
  }
  for (i = 0; i < C; ++i) {
    if (guppi_data_table_get_col_label (tab, i) != NULL)
      return FALSE;
  }

  return TRUE;
}

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

static gint changed = 0;
static gint changed_r = -1, changed_c = -1;

static void
changed_entry_cb (GuppiDataTable *tab, gint r0, gint c0, gint r1, gint c1)
{
  ++changed;

  if (r0 != r1)
    r0 = r1 = -1;
  
  if (c0 != c1)
    c0 = c1 = -1;

  changed_r = r0;
  changed_c = c0;
}

static gboolean
basic_ops (gpointer foo)
{
  GuppiDataTable *tab;
  gint i, j, k;
  gchar *str;

  guppi_test_subtest ("Constructing table");
  tab = GUPPI_DATA_TABLE (guppi_data_new ("GuppiDataTableCore"));
  if (tab == NULL)
    return FALSE;

  gtk_signal_connect (GTK_OBJECT (tab),
		      "changed_table_entries",
		      GTK_SIGNAL_FUNC (changed_entry_cb),
		      NULL);

  for (k = 0; k < 2; ++k) {
    gint R = 10 + 5 * k, C = 20 - 10 * k;

    str = guppi_strdup_printf ("Setting dimensions (pass #%d)", k+1);
    guppi_test_subtest (str);
    guppi_free (str);
    guppi_data_table_set_dimensions (tab, R, C);

    if (! sanity_check (tab, R, C))
      return FALSE;

    /* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
  
    guppi_test_subtest ("Get/Set entries");
    
    for (i = 0; i < guppi_data_table_get_row_count (tab); ++i) {
      for (j = 0; j < guppi_data_table_get_col_count (tab); ++j) {
	changed = 0;
	guppi_data_table_set_entry (tab, i, j, 18*i - 7*j);
	if (changed != 1 || changed_r != i || changed_c != j) {
	  g_print ("changed=%d changed_r=%d changed_c=%d i=%d j=%d\n", changed, changed_r, changed_c, i, j);
	  return FALSE;
	}
      }
    }

    for (i = 0; i < guppi_data_table_get_row_count (tab); ++i) {
      for (j = 0; j < guppi_data_table_get_col_count (tab); ++j) {
	if (guppi_data_table_get_entry (tab, i, j) !=  18*i - 7*j)
	  return FALSE;
      }
    }

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

    guppi_test_subtest ("Get/Set labels");

    for (i = 0; i < guppi_data_table_get_row_count (tab); ++i) {
      str = guppi_strdup_printf ("Row Label #%d", i);
      guppi_data_table_set_row_label (tab, i, str);
      guppi_free (str);
    }

    for (i = 0; i < guppi_data_table_get_col_count (tab); ++i) {
      str = guppi_strdup_printf ("Column Label #%d", i);
      guppi_data_table_set_col_label (tab, i, str);
      guppi_free (str);
    }

    for (i = 0; i < guppi_data_table_get_row_count (tab); ++i) {
      str = guppi_strdup_printf ("Row Label #%d", i);
      if (strcmp (guppi_data_table_get_row_label (tab, i), str))
	return FALSE;
      guppi_free (str);
    }

    for (i = 0; i < guppi_data_table_get_col_count (tab); ++i) {
      str = guppi_strdup_printf ("Column Label #%d", i);
      if (strcmp (guppi_data_table_get_col_label (tab, i), str))
	return FALSE;
      guppi_free (str);
    }

  }

  guppi_test_subtest ("Destroy");
  guppi_unref (tab);

  return TRUE;
}

static double *
slice (GuppiDataTable *tab, GuppiDataTableSpan span, gint i, gint *N)
{
  double *sl;
  gint n;
  gint j, r, c;

  GuppiDataTableSpan perp_span = span == GUPPI_TABLE_ROW ? GUPPI_TABLE_COL : GUPPI_TABLE_ROW;
  
  n = guppi_data_table_get_span_count (tab, perp_span);
  if (N)
    *N = n;
  sl = guppi_new (double, n);

  for (j = 0; j < n; ++j) {

    if (span == GUPPI_TABLE_ROW) {
      r = i;
      c = j;
    } else {
      r = j;
      c = i;
    }

    sl[j] = guppi_data_table_get_entry (tab, r, c);
	
  }

  return sl;
}

static gboolean
stats (gpointer ptr)
{
  GuppiDataTable *tab;
  GuppiDataTableSpan span;
  gint i, j, k, N;
  double *sl, sum, abs_sum, min, max, x;
  gboolean problem = FALSE;
  const gint R=62, C=220;

  guppi_test_subtest ("Constructing table");
  tab = GUPPI_DATA_TABLE (guppi_data_new ("GuppiDataTableCore"));
  if (tab == NULL)
    return FALSE;

  guppi_data_table_set_dimensions (tab, R, C);
  for (i = 0; i < R; ++i)
    for (j = 0; j < C; ++j)
      guppi_data_table_set_entry (tab, i, j, 7 + 38.32 * i - j * j );
  
  sanity_check (tab, R, C);

  guppi_test_subtest ("Verifying stats");
  for (k = 0; k < 2; ++k) {
    span = k ? GUPPI_TABLE_ROW : GUPPI_TABLE_COL;
    for (i = 0; i < guppi_data_table_get_span_count (tab, span); ++i) {

      sl = slice (tab, span, i, &N);
      
      sum = abs_sum = 0;
      min = max = sl[0];
      for (j = 0; j < N; ++j) {
	sum += sl[j];
	abs_sum += fabs (sl[j]);
	if (sl[j] < min)
	  min = sl[j];
	if (sl[j] > max)
	  max = sl[j];
      }
      
      if (! eq (sum, x = guppi_data_table_get_sum (tab, span, i))) {
	g_print ("bad sum (have %g, expected %g)\n", x, sum);
	problem = TRUE;
      }
      
      if (! eq (abs_sum, x = guppi_data_table_get_abs_sum (tab, span, i))) {
	g_print ("bad abs_sum (have %g, expected %g)\n", x, abs_sum);
	problem = TRUE;
      }
      
      if (! eq (min, x = guppi_data_table_get_min (tab, span, i))) {
	g_print ("bad min (have %g, expected %g)\n", x, min);
	problem = TRUE;
      }
      
      if (! eq (max, x = guppi_data_table_get_max (tab, span, i))) {
	g_print ("bad max (have %g, expected %g)\n", x, max);
	problem = TRUE;
      }

      if (problem) {
	for (i = 0; i < N; ++i)
	  g_print ("%g ", sl[i]);
	g_print ("\n");
	break;
      }
    }
    if (problem)
      break;
  }

  return ! problem;
  }

int
main (int argc, char *argv[])
{
  guppi_test_init (&argc, &argv);

  guppi_useful_init_without_guile ();
  guppi_data_init ();

  guppi_test_do ("Locate and load data table plug-ins",  plugins, NULL);
  guppi_test_do ("Create/destroy a GuppiDataTableCore",  construct, NULL);
  guppi_test_do ("Basic GuppiDataTable operations",      basic_ops, NULL);
  guppi_test_do ("GuppiDataTable statistics",            stats, NULL);

  guppi_test_quit ();
  return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1