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

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

#include <cassert>
#include <iostream>
#include <iomanip>
#include <stdexcept>
#include <cmath>
#include <cfloat>
#include <cstring>
#include "WImage/StillImage.hh"

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

static void dump (Image *img);

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

  Image *img1 = NEW (StillImage ());

  /*
   * Out directory should not exist!
   */
  try
    {
      img1->write ("/nogo/out.pgm");
      assert (0);
    }
  catch (const exception &error)
    {
      cout << "Expected exception caught: " << error.what () << endl;
      assert (strstr (error.what (), "writing") != NULL);
    }
  try
    {
      img1->read ("/nogo/in.pgm");
      assert (0);
    }
  catch (const exception &error)
    {
      cout << "Expected exception caught: " << error.what () << endl;
      assert (strstr (error.what (), "open") != NULL);
    }

  try
    {
      img1->write ("out.pxm");
      assert (0);
    }
  catch (const exception &error)
    {
      cout << "Expected exception caught: " << error.what () << endl;
      assert (strstr (error.what (), "unknown") != NULL);
    }
  try
    {
      img1->read ("/nogo/in.ra");
      assert (0);
    }
  catch (const exception &error)
    {
      cout << "Expected exception caught: " << error.what () << endl;
      assert (strstr (error.what (), "unknown") != NULL);
    }

  try
    {
      img1->read ("image.pgm");
    }
  catch (const exception &error)
    {
      cout << "read: Exception caught: " << error.what () << endl;
      assert (0);
    }

  assert (img1->size () == 16);

  for (int i = 0; i < img1->size (); i++)
    {
      assert (fabs (img1->at (i) - (coeff)i) < DBL_EPSILON);
    }

  for (int row = 0; row < img1->rows (); row++)
    {
      RowVector &rw = img1->row ();
      rw.go (row);
      for (int col = 0; col < img1->cols (); col++)
        {
          assert (fabs (img1->at (row, col) - rw.at (col)) < DBL_EPSILON);
        }
    }
  cout << "OK?" << endl;

  for (int col = 0; col < img1->cols (); col++)
    {
      ColumnVector &cw = img1->col ();
      cw.go (col);
      for (int row = 0; row < img1->rows (); row++)
        {
          assert (fabs (img1->at (row, col) - cw.at (row)) < DBL_EPSILON);
        }
    }


  Image *img2 = NEW (StillImage ());

  try
    {
      img2->read ("image.pgm");
    }
  catch (const exception &error)
    {
      cout << "read: Exception caught: " << error.what () << endl;
      assert (0);
    }

  assert (img1->equals (*img2));

  for (int i = 0; i < img2->size (); i++)
    {
      img2->to (i, img2->at (i) * 2.0);
    }

  assert (!img1->equals (*img2));

#ifdef PFI
  try
    {
      img2->write ("image.pfi", fn_raw);
    }
  catch (const exception &error)
    {
      cout << "write: Exception caught: " << error.what () << endl;
      assert (0);
    }
  DELETE (img2);

  img2 = img1->clone ();
  assert (img1->equals (*img2));

  img2->copy (*img1);
  assert (img1->equals (*img2));

  try
    {
      img2->read ("image.pfi", fn_raw, 4, 4);
    }
  catch (const exception &error)
    {
      cout << "read: Exception caught: " << error.what () << endl;
      assert (0);
    }

  for (int i = 0; i < img2->size (); i++)
    {
      img2->to (i, img2->at (i) / 2.0);
    }

  assert (img1->equals (*img2));

  try
    {
      img2->write ("image.pfi");
    }
  catch (const exception &error)
    {
      cout << "write: Exception caught: " << error.what () << endl;
      assert (0);
    }

  try
    {
      img2->read ("image.pfi");
    }
  catch (const exception &error)
    {
      cout << "read: Exception caught: " << error.what () << endl;
      assert (0);
    }

  assert (img1->equals (*img2));

  img1->normalize (2);

  for (int i = 0; i < img1->size (); i++)
    {
      assert (fabs (img1->at (i) - (coeff)i/2.0) < DBL_EPSILON);
    }

  img1->unnormalize (2);

  for (int i = 0; i < img1->size (); i++)
    {
      assert (fabs (img1->at (i) - (coeff)i) < DBL_EPSILON);
    }
#endif

  dump (img1);

  pixel *ar = img1->exportPixels ();
  img2->importPixels (img1->rows (), img1->cols (), ar);
  DELETE (ar);

  assert (img1->equals (*img2));

  coeff *br = img1->exportCoeffs ();
  img2->importCoeffs (img1->rows (), img1->cols (), br);
  DELETE (br);

  assert (img1->equals (*img2));

  DELETE (img1);
  DELETE (img2);

  img1 = NEW (StillImage (4, 4));

  for (int i = 0; i < img1->size (); i++)
    {
      img1->to (i, i);
    }

  img2 = NEW (StillImage (2, 8));

  try
    {
      img1->iproduct (*img2);
      assert (0);
    }
  catch (const exception &error)
    {
      cout << "Expected exception caught: " << error.what () << endl;
    }
  DELETE (img2);

  img2 = img1->clone ();
  assert (img1->equals (*img2));

  cout.setf (ios::fixed, ios::floatfield);

  cout << "Inner product two identical images: "
       << std::setw (2) << img1->iproduct (*img2) << endl;

  for (int i = 0; i < img1->size (); i++)
    {
      img1->to (i, 0);
      img2->to (i, 0);
    }
  img1->to (0, 1);
  img2->to (0, -1);
  img1->to (1, 1);
  img2->to (1, 1);

  assert (fabs (img1->iproduct (*img2)) < COEFF_EPSILON);

  cout << "Inner product two orthogonal images: "
       << std::setw (2) << img1->iproduct (*img2) << endl;

  cout.setf (FMT0, ios::floatfield);

  DELETE (img1);
  DELETE (img2);

  cout << "Test of class Image and subclasses completed successfully.\n";
  return 0;
}

static void
dump (Image *img)
{
  RowVector &rw = img->row ();
  cout.setf (ios::fixed, ios::floatfield);
  for (int row = 0; row < img->rows (); row++)
    {
      rw.go (row);
      cout << "[" << std::setw (2) << std::setfill (' ') << row << "] ";
      for (int col = 0; col < rw.size (); col++)
        {
          cout << std::setprecision (1) << std::setw (4) << rw.at (col)
            /*<< "/"
              << std::setprecision (1) << std::setw (4) << img->at (row, col)*/
               << ' ';
        }
      cout << endl;
    }
  cout.setf (FMT0, ios::floatfield);
}

