/*
 * Test program for the class PyramidTransform
 *
 * This is a rather poor test, since only misc functions are tested. The
 * main decomposition and reconstruction algorithms are stolen and thus
 * supposed to work.
 *
 * $Date$
 * $Revision$
 *
 */

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

#include "WImage/StillImage.hh"
#include "Wave/PyramidTransform.hh"
#include "Wave/StandardTransform.hh"
#include "testing.h"
#include <cassert>
#include <iostream>
#include <iomanip>
#include <cmath>

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

static void
wavelet (void)
{
  cout << "Testing class WaveletTransform...\n";
  int steps = 1;
  Image *image = NEW(StillImage ());
  TEST_NO_EXCEPTION (image->read ("harin5.pgm"));
  WaveletTransform * transform = NEW (PyramidTransform (*image, Haar));
  TEST_NO_EXCEPTION (transform->analysis (steps));

  Image *himax = transform->highMax();

  int yoffs = 0, xoffs = 0, ysize = 0, xsize = 0;
  area what;

  for (int a = (int)HL; a < (int)areaINVALID; a++)
    {
      what = (area)a;
      transform->where (what, steps, yoffs, xoffs, ysize, xsize);
      for (int y = 0; y < himax->rows (); y++)
	{
	  for (int x = 0; x < himax->cols (); x++)
	    {
	      TEST_ASSERT (fabs (himax->at(y, x)) + FLT_EPSILON
			   >= fabs (image->at (y + yoffs, x + xoffs)));
	    }
	}
    }

  DELETE(image);
  DELETE(transform);
  DELETE(himax);
  cout << "Test of class WaveletTransform completed successfully.\n";
}

static void
pyramid (void)
{
  cout << "Testing class PyramidTransform...\n";

  Image *image = NEW (StillImage (8, 8));
  WaveletTransform * transform = NEW (PyramidTransform (*image, Daub4));

  for (int row = 0; row < 8; row++)
    {
      for (int col = 0; col < 8; col++)
        {
          assert (transform->getSubband (row, col) == 0);
        }
    }

  image->anasteps (1);

  for (int row = 0; row < 8; row++)
    {
      for (int col = 0; col < 8; col++)
        {
          assert (transform->getSubband (row, col) == 1);
        }
    }

  image->anasteps (2);

  for (int row = 4; row < 8; row++)
    {
      for (int col = 4; col < 8; col++)
        {
          assert (transform->getSubband (row, col) == 1);
        }
    }

  for (int row = 0; row < 4; row++)
    {
      for (int col = 0; col < 4; col++)
        {
          assert (transform->getSubband (row, col) == 2);
        }
    }

  for (int row = 4; row < 8; row++)
    {
      for (int col = 4; col < 8; col++)
        {
          assert (transform->getSubband (row, col, 3) == 1);
        }
    }

  for (int row = 2; row < 4; row++)
    {
      for (int col = 2; col < 4; col++)
        {
          assert (transform->getSubband (row, col, 3) == 2);
        }
    }

  for (int row = 0; row < 2; row++)
    {
      for (int col = 0; col < 2; col++)
        {
          assert (transform->getSubband (row, col, 3) == 3);
        }
    }

  DELETE (image);
  DELETE (transform);
  image = NEW (StillImage ());
  try
    {
      image->read ("lena128.pgm");
    }
  catch (const exception &error)
    {
      cerr << "Error reading file: " << error.what () << endl;
      assert (0);
    }

  transform = NEW (PyramidTransform (*image, Daub4));
  image->anasteps (3);
  int yoffs, xoffs, ysize, xsize;

  transform->where (HH, 1, yoffs, xoffs, ysize, xsize);
  assert (yoffs == 64);
  assert (xoffs == 64);
  assert (ysize == 64);
  assert (xsize == 64);
  transform->where (HH, 2, yoffs, xoffs, ysize, xsize);
  assert (yoffs == 32);
  assert (xoffs == 32);
  assert (ysize == 32);
  assert (xsize == 32);

  transform->where (LL, 1, yoffs, xoffs, ysize, xsize);
  assert (yoffs == 0);
  assert (xoffs == 0);
  assert (ysize == 64);
  assert (xsize == 64);

  transform->where (LL, 2, yoffs, xoffs, ysize, xsize);
  assert (yoffs == 0);
  assert (xoffs == 0);
  assert (ysize == 32);
  assert (xsize == 32);

  transform->where (LH, 1, yoffs, xoffs, ysize, xsize);
  assert (yoffs == 64);
  assert (xoffs == 0);
  assert (ysize == 64);
  assert (xsize == 64);

  transform->where (HL, 1, yoffs, xoffs, ysize, xsize);
  assert (yoffs == 0);
  assert (xoffs == 64);
  assert (ysize == 64);
  assert (xsize == 64);

  transform->where (LH, 2, yoffs, xoffs, ysize, xsize);
  assert (yoffs == 32);
  assert (xoffs == 0);
  assert (ysize == 32);
  assert (xsize == 32);

  transform->where (HL, 2, yoffs, xoffs, ysize, xsize);
  assert (yoffs == 0);
  assert (xoffs == 32);
  assert (ysize == 32);
  assert (xsize == 32);

  assert (fabs (transform->ratio (1, 1) - 1) < COEFF_EPSILON);
  assert (fabs (transform->ratio (2, 2) - 1) < COEFF_EPSILON);
  assert (fabs (transform->ratio (1, 2) - 4) < COEFF_EPSILON);
  assert (fabs (transform->ratio (2, 1) - 1.0/4.0) < COEFF_EPSILON);
  assert (fabs (transform->ratio (1, 3) - 16) < COEFF_EPSILON);
  assert (fabs (transform->ratio (3, 1) - 1.0/16.0) < COEFF_EPSILON);
  //cout << yoffs << "/" << xoffs << " to: "
  //     << yoffs+ysize << "/" << xoffs+xsize << endl;

  int subband;
  area channel;
  yoffs = xoffs = 0;
  transform->where (yoffs, xoffs, subband, channel, 2);
  assert (subband == 2);
  assert (channel == LL);
  transform->where (yoffs, xoffs, subband, channel);
  assert (subband == 3);
  assert (channel == LL);

  yoffs = xoffs = 31;
  transform->where (yoffs, xoffs, subband, channel, 2);
  assert (subband == 2);
  assert (channel == LL);
  transform->where (yoffs, xoffs, subband, channel);
  assert (subband == 3);
  assert (channel == HH);

  yoffs = xoffs = 32;
  transform->where (yoffs, xoffs, subband, channel, 2);
  assert (subband == 2);
  assert (channel == HH);

  yoffs = xoffs = 64;
  transform->where (yoffs, xoffs, subband, channel, 2);
  assert (subband == 1);
  assert (channel == HH);

  yoffs = xoffs = 127;
  transform->where (yoffs, xoffs, subband, channel, 2);
  assert (subband == 1);
  assert (channel == HH);

  yoffs = 32;
  xoffs = 1;
  transform->where (yoffs, xoffs, subband, channel, 2);
  assert (subband == 2);
  assert (channel == LH);

  yoffs = 1;
  xoffs = 32;
  transform->where (yoffs, xoffs, subband, channel, 2);
  assert (subband == 2);
  assert (channel == HL);
  //cout << yoffs << "/" << xoffs
  //     << "-> subband: " << subband << ", channel: " << (int)channel << endl;

  try
    {
      image->read ("lena128_98.pgm");
    }
  catch (const exception &error)
    {
      cerr << "Error reading file: " << error.what () << endl;
      assert (0);
    }
  transform->where (LL, 1, yoffs, xoffs, ysize, xsize);
  assert (yoffs == 0);
  assert (xoffs == 0);
  assert (ysize == 49);
  assert (xsize == 64);

  transform->where (HH, 1, yoffs, xoffs, ysize, xsize);
  assert (yoffs == 49);
  assert (xoffs == 64);
  assert (ysize == 49);
  assert (xsize == 64);

  transform->where (LH, 1, yoffs, xoffs, ysize, xsize);
  assert (yoffs == 49);
  assert (xoffs == 0);
  assert (ysize == 49);
  assert (xsize == 64);

  transform->where (HL, 1, yoffs, xoffs, ysize, xsize);
  assert (yoffs == 0);
  assert (xoffs == 64);
  assert (ysize == 49);
  assert (xsize == 64);

  DELETE (image);
  DELETE (transform);
  cout << "Test of class PyramidTransform completed successfully.\n";
}

/* Currently identical to pyramid, but what the fsck... */
static void
standard (void)
{
  cout << "Testing class StandardTransform...\n";

  Image *image = NEW (StillImage (8, 8));
  StandardTransform transform (*image, Daub4);

  for (int row = 0; row < 8; row++)
    {
      for (int col = 0; col < 8; col++)
        {
          assert (transform.getSubband (row, col) == 0);
        }
    }

  image->anasteps (1);

  for (int row = 0; row < 8; row++)
    {
      for (int col = 0; col < 8; col++)
        {
          assert (transform.getSubband (row, col) == 1);
        }
    }

  image->anasteps (2);

  for (int row = 4; row < 8; row++)
    {
      for (int col = 4; col < 8; col++)
        {
          assert (transform.getSubband (row, col) == 1);
        }
    }

  for (int row = 0; row < 4; row++)
    {
      for (int col = 0; col < 4; col++)
        {
          assert (transform.getSubband (row, col) == 2);
        }
    }

  for (int row = 4; row < 8; row++)
    {
      for (int col = 4; col < 8; col++)
        {
          assert (transform.getSubband (row, col, 3) == 1);
        }
    }

  for (int row = 2; row < 4; row++)
    {
      for (int col = 2; col < 4; col++)
        {
          assert (transform.getSubband (row, col, 3) == 2);
        }
    }

  for (int row = 0; row < 2; row++)
    {
      for (int col = 0; col < 2; col++)
        {
          assert (transform.getSubband (row, col, 3) == 3);
        }
    }

  DELETE (image);

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

int
main (void)
{
  wavelet ();
  pyramid ();
  standard ();
  return 0;
}

