/*
 * Compare two PGM images
 *
 * $Date$
 * $Revision$
 *
 */

#include <iostream>
#include <iomanip>
#include <stdexcept>
#include <cassert>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <WTools.hh>

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

static bool
power2 (int num)
{
  int i;
  for (i = 2; i < num; i *= 2)
    {
    }
  return i == num;
}

static void
sizecheck (Image *img)
{
  int x = img->cols (), y = img->rows ();
  if (x != y || !power2 (x))
    {
      int newsize = x < y? y: x;
      if (!power2 (newsize))
        {
          int i;
          for (i = 2; i < newsize; i *= 2)
            {
            }
          newsize = i;
        }
      img->resize (newsize, newsize);
    }
}

int
main (int argc, char *argv[])
{
  Image *img1 = NEW (StillImage ());
  Image *img2 = NEW (StillImage ());
  double percent = 1;
  FilterSet &filter = Haar;
  imgtype type = SCANNED;
  bool simple = false;
  int myArgc = argc;
  char **myArgv = argv;

  /* Preliminary steps */

  cerr << "pgmcompare version " << WAVE_VERSION << " (c) 2001-2004 by Herbert"
#ifdef PFI
       << " (pfi support enabled)"
#endif
       << endl;

  if (argc > 3 && strcmp (argv[1], "-s") == 0)
    {
      simple = true;
      myArgc--;
      myArgv++;
    }

  if (myArgc < 3 || myArgc > 5)
    {
      cerr << "Usage: pgmcompare [-s] <file1> <file2> [<percent> [<type>]]"
           << endl
           << "       default for percent is " << percent << endl
           << "       types are: 0 (drawn) or 1 (scanned)" << endl
           << "       `-s' stands for `simple' (no L^q and L^qd)" << endl;
      return 1;
    }
  if (myArgc > 3)
    {
      if (sscanf (myArgv[3], "%lf", &percent) != 1)
        {
          cerr << "Invalid percent: " << myArgv[3] << endl;
          return 1;
        }
    }

  if (myArgc > 4)
    {
      int i;
      if (sscanf (myArgv[4], "%d", &i) != 1 || (i & ~0x1))
        {
          cerr << "Invalid type: " << myArgv[4] << endl;
          return 1;
        }
      type = (imgtype)i;
    }

  try
    {
      img1->read (myArgv[1]);
    }
  catch (const exception &error)
    {
      cerr << "Reading first image: " << error.what () <<endl;
      return 1;
    }

  try
    {
      img2->read (myArgv[2]);
    }
  catch (const exception &error)
    {
      cerr << "Reading second image: " << error.what () <<endl;
      return 1;
    }

  /* do not resize for simple operations */
  if (!simple)
    {
      sizecheck (img1);
      sizecheck (img2);
    }

  /* Calculate the simple statistics */

  double mse;
  double rmse;
  double psnr;
  lq score;
  double lqd_norm;
  ImageComparison *comparison = NEW (ImageComparison (*img1, *img2));

  mse  = comparison->cmpmse ();
  rmse = sqrt (mse);
  psnr = (mse == 0? -1: comparison->cmpsnr ());

  cout.setf (ios::fixed, ios::floatfield);
  cout << "MSE: "  << std::setprecision (5) << std::setw (11) << mse << endl
       << "RMSE: " << std::setprecision (5) << std::setw (10) << rmse << endl
       << "PSNR: ";
  if (psnr < 0)
    {
      cout << "Infinite (identical images)" << endl;
    }
  else
    {
      cout << std::setprecision (5) << std::setw (10) << psnr << endl;
    }

  if (simple)
    {
      goto cleanup;
    }

  try
    {
      score = comparison->distlq (percent, filter, type);
      lqd_norm = comparison->distlqd (percent, filter, type);
    }
  catch (exception &error)
    {
      cerr << "Performing comparison: " << error.what () << endl;
      cerr << "Not calculating L^q and Lq_d metrics." << endl;
      return 1;
    }

  DELETE (comparison);

  /* Print the statistics */

  cout << "L^q: " << std::setprecision (5) << std::setw (11)
       << score.colors + score.details << endl;
  cout << "Lq_d: " << std::setprecision (5) << std::setw (10)
       << lqd_norm << endl;

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

cleanup:

  DELETE (img1);
  DELETE (img2);

  return 0;
}

