/*
 * Test program for the class Wavelet and its subclasses
 *
 * $Date$
 * $Revision$
 *
 */

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

#ifndef DPRINTF
#define DPRINTF(x)
#endif

#include <cstdio>
#include <cassert>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <cfloat>
#include "../ImageArray.cc"
#include "WImage/RowVector.hh"
#include "Wave/Wavelet.hh"

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

static void dump (ImageArray<coeff> *ia);
static void generic (ImageArray<coeff> *ia, FilterSet *fset, int substeps);

int
main (void)
{
  cout << "Testing class Wavelet and subclasses...\n";

  struct filter {
    FilterSet *filterset;
    const char *name;
    int substeps;
  } filters[] = {
    {&Haar, "Haar", 0}, {&Daub4, "Daub4", 0}, {&Daub6, "Daub6", 0}, 
    {&Daub8, "Daub8", 0}, {&Villa3, "Villa3", 1}, 
    {&Villa5, "Villa5", 1}, {&Antonini, "Antonini", 1}, 
    {&Brislawn, "Brislawn", 1}, {&Villa1, "Villa1", 1}, 
    {&Villa2, "Villa2", 1}, {&Villa4, "Villa4", 1}, 
    {&Villa6, "Villa6", 1}, {&Odegard, "Odegard", 1}
  };
  int filternum = sizeof filters / sizeof (*filters);

  ImageArray<coeff> *ia1 = NEW (ImageArray<coeff> (1, 8));

  for (int i = 0; i < filternum; i++)
    {
      
      for (int j = 0; j < ia1->size (); j++)
        {
          ia1->to (j, (coeff)j);
        }

      cout << filters[i].name << endl;
      generic (ia1, filters[i].filterset, filters[i].substeps);
    }
  
  DELETE (ia1);

  ImageArray<coeff> *ia2 = NEW (ImageArray<coeff> (1, 9));

  cout << "FIXME: Skipping filters Haar, Daub4, Daub6, Daub8, Villa3, Villa5"
       << endl << "       for known reasons (see README file)." << endl;
  for (int i = 6; i < filternum; i++)
    {
      
      for (int j = 0; j < ia2->size (); j++)
        {
          ia2->to (j, (coeff)j);
        }

      cout << filters[i].name << endl;
      generic (ia2, filters[i].filterset, filters[i].substeps);
    }
  
  DELETE (ia2);
  
  cout << "Test of class Wavelet and subclasses completed successfully.\n";
  return 0;
}

static void generic (ImageArray<coeff> *ia, FilterSet *fset, int substeps)
{
  Wavelet w (*fset);
  
  RowVector *rw = NEW (RowVector (ia));
  rw->go (0);

  ImageArray<coeff> *ia2 = NEW (ImageArray<coeff> (ia->rows (), ia->cols ()));
  RowVector *rw2 = NEW (RowVector (ia2));
  rw2->go (0);

  assert (rw->size () == rw2->size ());

  ImageArray<coeff> *ia3 = ia->clone ();
  
  dump (ia3);

  try 
    {
      w.analysis (*rw2, *rw, 3-substeps);
    }
  catch (const exception &error)
    {
      cerr << "Exception caught: " << error.what () << endl;
      assert (0);
    }
  
  dump (ia2);

  try 
    {
      w.synthesis (*rw, *rw2, 3-substeps, 3-substeps);
    }
  catch (const exception &error)
    {
      cerr << "Exception caught: " << error.what () << endl;
      assert (0);
    }

  dump (ia);

  for (int y = 0; y < ia->rows (); y++)
    {
      for (int x = 0; x < ia->cols (); x++)
        {
          assert (fabs (ia->at (y, x) - ia3->at (y, x)) < 1.0e-9);
        }
    }
  DELETE (rw);
  DELETE (rw2);
  DELETE (ia2);
  DELETE (ia3);
}


static void 
dump (ImageArray<coeff> *ia)
{
  cout.setf (ios::fixed, ios::floatfield);
  for (int row = 0; row < ia->rows (); row++)
    {
      cout << "[" << std::setw (2) << std::setfill (' ') << row << "] ";
      for (int col = 0; col < ia->cols (); col++)
        {
          cout << std::setprecision (4) << std::setw (7) 
               << ia->at (row, col) << ' ';
        }
      cout << endl;
    }
  cout.setf (FMT0, ios::floatfield);
}
