/*
 * Test program for class ImageArray
 *
 * $Date$
 * $Revision$
 *
 */

#ifdef NDEBUG
#undef NDEBUG
#endif /* NDEBUG */

/* turn off debug output from tested class... */
#ifndef DPRINTF
#define DPRINTF(x)
#endif

#include <cassert>
#include <cstring>
#include <iostream>
#include <iomanip>
#include "WImage/debug.h"
#include "../ImageArray.cc"

#if !(defined __WATCOMC__ && __WATCOMC__ < 1230)
using namespace std;
#endif

static void 
dump (ImageArray<int> *ia)
{
  for (int row = 0; row < ia->rows (); row++)
    {
      cout << "[" << std::setw (2) << std::setfill (' ') << row << "] ";
      for (int col = 0; col < ia->cols (); col++)
        {
          cout << ia->at (row, col) << ' ';
        }
      cout << endl;
    }
}

int
main (void)
{
  cout << "Testing class ImageArray...\n";

  int x = 0, y = 0;
  ImageArray<int> *ia = NEW (ImageArray<int> (y, x));
  DELETE (ia);

  x = 3, y = 3;
  ia = NEW (ImageArray<int> (y, x));

  /*
   * Constructor, array export and attributes test...
   */
  assert (ia->rows () == y);
  assert (ia->cols () == x);
  assert (ia->size () == x*y);

  /*
   * Writing array member reference...
   */
  ia->to (0, 1, 1);
  assert (ia->at (0, 1) == 1);
  
  /*
   * Fill the array...
   */
  for (int i = 0; i < ia->size (); i++)
    {
      ia->to (0, i, i);
      assert (ia->at (0, i) == i);
      assert (ia->array () [i] == i);
    }
  cout << ia->smax () << " " << ia->amax () << endl;
  
  assert (ia->smax () == ia->size () -1);
  assert (ia->amax () == ia->size () -1);

  ia->to (0, 0, (ia->at (ia->rows () - 1, ia->cols () - 1) + 1) * (-1));
  assert (ia->smin () == -1 * ia->amax ());
  ia->to (0, 0, (ia->at (0, 0) * (-1) - 1));
  assert (ia->smin () == ia->amin ());
  assert (ia->amin () == ia->at (0, 1));
  ia->to (0, 0, 0);

  /*
   * Test the clone() method. Values must be the same, but not the 
   * addresses... 
   * We can now also test the equals () method...
   */
  ImageArray<int> *ia2 = ia->clone ();
  assert (ia->rows () == ia2->rows ());
  assert (ia->cols () == ia2->cols ());
  assert (ia->size () == ia2->size ());
  for (int row = 0; row < ia->rows (); row++)
    {
      for (int col = 0; col < ia->cols (); col++)
        {
          assert (ia->at (row, col) == ia2->at (row, col));
        }
    }
  assert (ia->equals (*ia2) && ia2->equals (*ia));

  /*
   * The resize method can be tricky...
   */
  ia->resize (y+1, x+1);
  assert (ia->rows () == y+1);
  assert (ia->cols () == x+1);
  assert (ia->size () == (x+1)*(y+1));

  /*
   * We now have two different arrays!
   */
  assert (!ia->equals (*ia2));
  
  /*
   * When growing, the line ends and empty lines get filled with 0s.
   * After resizing (shrinking) to original size it should be the same
   * as the clone again.
   */
  for (int i = 0; i < ia->rows () - 1; i++)
    {
      assert (ia->at (i, x) == 0);
    }
  for (int i = 0; i < ia->cols (); i++)
    {
      assert (ia->at (ia->rows () - 1, i) == 0);
    }
  
  /*dump (ia);*/
  ia->resize (y, x);
  /*dump (ia2);
    dump (ia);*/
  assert (ia->equals (*ia2));

  /*
   * Now we resize to not overall bigger and not overall smaller...
   * First pass: 2 rows, 4 columns:
   */
  ia->resize (y-1, x+1);
  assert (ia->rows () == y-1);
  assert (ia->cols () == x+1);
  assert (ia->size () == (x+1)*(y-1));
  assert (!ia->equals (*ia2));
  assert (ia->at (0, x) == 0 && ia->at (1, x) == 0);

  /*
   * Second pass: 4 rows, 2 columns:
   */
  ia->resize (y+1, x-1);
  assert (ia->rows () == y+1);
  assert (ia->cols () == x-1);
  assert (ia->size () == (x-1)*(y+1));
  assert (!ia->equals (*ia2));
  assert (ia->at (y-1, 0) == 0 && ia->at (y-1, 1) == 0);
  assert (ia->at (y, 0) == 0 && ia->at (y, 1) == 0);

  /*
   * Third pass: produce a real big one:
   */
  x = y = 40;
  ia->resize (y, x);
  assert (ia->rows () == y);
  assert (ia->cols () == x);
  assert (ia->size () == y*x);
  assert (!ia->equals (*ia2));
  assert (ia->at (y-1, 0) == 0 && ia->at (0, x-1) == 0);
  assert (ia->at (y-1, x-1) == 0);
  ia->to (y-1, x-1, 1);
  ia->to (0, 0, 9);

  DELETE (ia2);

  /*
   * Forth pass: produce a real small one:
   */
  x = y = 1;
  ia->resize (y, x);
  assert (ia->rows () == y);
  assert (ia->cols () == x);
  assert (ia->size () == y*x);
  assert (ia->at (0, 0) == 9);
  
  /* Try out asymmetric resizing and then compare: find row/col 
   * messup if there is any */
  ia->resize (2 * y, x);
  ImageArray<int> *dummy = ia->clone ();
  assert (dummy->equals (ia));
  DELETE (dummy);
  ia->resize (y, 2 * x);
  dummy = ia->clone ();
  assert (dummy->equals (ia));
  DELETE (dummy);

  /*
   * Final pass: exception handling in resize()
   */
  try 
    {
      ia->resize (-1, 0);
      assert (0);
    }
  catch (const exception &error)
    {
      cout << "Expected exception caught: " << error.what () << endl;
      assert (strstr (error.what (), "negative") != NULL);
    }
  try 
    {
      ia->resize (0, -1);
      assert (0);
    }
  catch (const exception &error)
    {
      cout << "Expected exception caught: " << error.what () << endl;
      assert (strstr (error.what (), "negative") != NULL);
    }
  try 
    {
      ia->resize (-1, -1);
      assert (0);
    }
  catch (const exception &error)
    {
      cout << "Expected exception caught: " << error.what () << endl;
      assert (strstr (error.what (), "negative") != NULL);
    }
  try 
    {
      ia->resize (0, 0);
      assert (0);
    }
  catch (const exception &error)
    {
      cout << "Expected exception caught: " << error.what () << endl;
      assert (strstr (error.what (), "zero") != NULL);
    }
  
  dump (ia);

  ia->resize (5, 4);
  for (int i = 0; i < ia->size (); i++)
    {
      ia->to (i, i+1);
    }

  assert (ia->saverage () == 10);
  assert (ia->aaverage () == 10);
  assert (ia->saverage (0, 0, -1, -1) == 10);
  assert (ia->saverage (0, 0, 1, 1) == 1);
  assert (ia->saverage (4, 3, -1, -1) == 20);
  
  DELETE (ia);

  cout << "Test of class ImageArray completed successfully.\n";

  return 0;
}
