/********************************************************************\
 * cellblock.c -- group of cells that act as cursor within a table  *
 *                                                                  *
 * 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, contact:                        *
 *                                                                  *
 * Free Software Foundation           Voice:  +1-617-542-5942       *
 * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
 * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
 *                                                                  *
\********************************************************************/

/*
 * FILE:
 * cellblock.c
 * 
 * FUNCTION:
 * implements a rectangular array of cells. See the header file for
 * additional documentation.
 *
 * HISTORY:
 * Copyright (c) 1998 Linas Vepstas
 * Copyright (c) 2000-2001 Dave Peticolas <dave@krondo.com>
 */

#include "config.h"

#include "cellblock.h"

static void gnc_cellblock_init (CellBlock *cellblock, int rows, int cols);


CellBlock *
gnc_cellblock_new (int rows, int cols, const char *cursor_name)
{
  CellBlock *cellblock;

  g_return_val_if_fail (rows > 0, NULL);
  g_return_val_if_fail (cols > 0, NULL);
  g_return_val_if_fail (cursor_name != NULL, NULL);

  cellblock = g_new0 (CellBlock, 1);

  gnc_cellblock_init (cellblock, rows, cols);

  cellblock->cursor_name = g_strdup (cursor_name);

  return cellblock;
}

static void
gnc_cellblock_init (CellBlock *cellblock, int rows, int cols)
{
  /* record new size */
  cellblock->num_rows = rows;
  cellblock->num_cols = cols;

  cellblock->start_col = cols;
  cellblock->stop_col  = -1;

  /* malloc new cell table */
  cellblock->cells = g_ptr_array_new ();

  g_ptr_array_set_size (cellblock->cells, rows * cols);
}

void        
gnc_cellblock_destroy (CellBlock *cellblock)
{
   if (!cellblock) return;

   g_ptr_array_free (cellblock->cells, FALSE);
   cellblock->cells = NULL;

   g_free (cellblock->cursor_name);
   cellblock->cursor_name = NULL;

   g_free (cellblock);
}

void
gnc_cellblock_set_cell (CellBlock *cellblock,
                        int row, int col,
                        BasicCell *cell)
{
  if (cellblock == NULL)
    return;

  if (row < 0 || row >= cellblock->num_rows)
    return;

  if (col < 0 || col >= cellblock->num_cols)
    return;

  cellblock->cells->pdata[(row * cellblock->num_cols) + col] = cell;
}

BasicCell *
gnc_cellblock_get_cell (CellBlock *cellblock, int row, int col)
{
  if (cellblock == NULL)
    return NULL;

  if (row < 0 || row >= cellblock->num_rows)
    return NULL;

  if (col < 0 || col >= cellblock->num_cols)
    return NULL;

  return cellblock->cells->pdata[(row * cellblock->num_cols) + col];
}

int
gnc_cellblock_changed (CellBlock *cursor, gboolean include_conditional)
{
  int changed = 0;
  int r, c;

  if (!cursor)
    return FALSE;

  for (r = 0; r < cursor->num_rows; r++)
    for (c = 0; c < cursor->num_cols; c++)
    {
      BasicCell *cell;

      cell = gnc_cellblock_get_cell (cursor, r, c);
      if (cell == NULL)
        continue;

      if (gnc_basic_cell_get_changed (cell))
      {
        changed++;
        continue;
      }

      if (include_conditional &&
          gnc_basic_cell_get_conditionally_changed (cell))
        changed++;
    }

  return changed;
}

void
gnc_cellblock_clear_changes (CellBlock *cursor)
{
  int r, c;

  if (!cursor)
    return;

  for (r = 0; r < cursor->num_rows; r++)
    for (c = 0; c < cursor->num_cols; c++)
    {
      BasicCell *cell;

      cell = gnc_cellblock_get_cell (cursor, r, c);
      if (cell == NULL)
        continue;

      gnc_basic_cell_set_changed (cell, FALSE);
      gnc_basic_cell_set_conditionally_changed (cell, FALSE);
    }
}
