/*
 * Scale an image
 *
 * $Date$
 * $Revision$
 *
 */

#include <iostream>
#include <stdexcept>
#include <cstdio>
#include <cmath>
#include <cassert>
#include <Wave.hh>

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

int
main (int argc, char *argv[])
{
  cout << "pgmscale version " << WAVE_VERSION << " (c) 2001-2004 by Herbert"
#ifdef PFI
       << " (pfi support enabled)"
#endif
       << endl;

  char *infile;
  char *outfile;
  Image *image1 = NEW (StillImage ());
  coeff factor;
  int stages = 0;
  int function = 0;
  FilterSet *filter = &Daub4;

  if (argc < 4 || argc > 9)
    {
      cerr << "Usage: pgmscale <infile> <outfile> <factor> [optional]" << endl;
      cerr << "Optional: [<function> [<stages> [<filter> [hlfunc [lhfunc]]]]]"
           << endl;
      return 1;
    }

  infile = argv[1];
  outfile = argv[2];

  if (sscanf (argv[3], "%lf", &factor) != 1)
    {
      cerr << "Invalid factor: " << argv[3] << endl;
      return 1;
    }

  if (argc > 5)
    {
      if (sscanf (argv[5], "%d", &stages) != 1 || stages < 0)
        {
          cerr << "Invalid stages: " << argv[5] << endl;
          return 1;
        }
    }

  if (argc > 6)
    {
      try
        {
          filter = &FilterSet::filterFromString (argv[6]);
        }
      catch (const exception &error)
        {
          cerr << "Error, : " << error.what () << endl;
          return 1;
        }
    }

  if (argc > 4)
    {
      if (sscanf (argv[4], "%d", &function) != 1)
        {
          cerr << "Invalid function: " << argv[4] << endl;
          return 1;
        }
    }

  int hlfunc = -1;
  int lhfunc = -1;

  if (argc > 7)
    {
      if (sscanf (argv[7], "%d", &hlfunc) != 1)
        {
          cerr << "Invalid function: " << argv[7] << endl;
          return 1;
        }
    }

  if (argc > 8)
    {
      if (sscanf (argv[8], "%d", &lhfunc) != 1)
        {
          cerr << "Invalid function: " << argv[8] << endl;
          return 1;
        }
    }


  try
    {
      image1->read (infile);
    }
  catch (const exception &error)
    {
      cerr << "Reading image: " << error.what () << endl;
      return 1;
    }

  WaveletTransform *transform = NULL;

  if (stages > 1)
    {
      transform = NEW (PyramidTransform (*image1, *filter));
      try
        {
          transform->analysis (stages);
        }
      catch (const exception &error)
        {
          cerr << "Analysis: " << error.what () <<endl;
          return 1;
        }
    }

  Image *image2 = NULL;

  Image **lh = NULL;
  Image **hl = NULL;

  if (stages > 1 && lhfunc >= 0)
    {
      lh = NEW (Image* [stages]);
      for (int i = 0; i < stages; i++)
        {
          Image *tmp = transform->lh (i + 1);
          try
            {
              lh[i] = tmp->scale (factor, lhfunc);
            }
          catch (const exception &error)
            {
              cerr << "Error: " << error.what () << endl;
              return 1;
            }
          DELETE (tmp);
        }
    }

  if (stages > 1 && hlfunc >= 0)
    {
      hl = NEW (Image* [stages]);
      for (int i = 0; i < stages; i++)
        {
          Image *tmp = transform->hl (i + 1);
          try
            {
              hl[i] = tmp->scale (factor, hlfunc);
            }
          catch (const exception &error)
            {
              cerr << "Error: " << error.what () << endl;
              return 1;
            }
          DELETE (tmp);
        }
    }

  try
    {
      image2 = image1->scale (factor, function);
    }
  catch (const exception &error)
    {
      cerr << "Error: " << error.what () << endl;
      return 1;
    }

  DELETENOTNULL (transform);

  if (stages > 1)
    {
      transform = NEW (PyramidTransform (*image2, *filter));

      if (lhfunc >= 0)
        {
          int yoffs, xoffs, ysize, xsize;
          for (int i = 0; i < stages; i++)
            {
              transform->where (LH, i + 1, yoffs, xoffs, ysize, xsize);
              image2->paste (yoffs, xoffs, *lh[i]);
              DELETE (lh[i]);
            }
          DELETE (lh);
        }

      if (hlfunc >= 0)
        {
          int yoffs, xoffs, ysize, xsize;
          for (int i = 0; i < stages; i++)
            {
              transform->where (HL, i + 1, yoffs, xoffs, ysize, xsize);
              image2->paste (yoffs, xoffs, *hl[i]);
              DELETE (hl[i]);
            }
          DELETE (hl);
        }
      try
        {
          transform->synthesis (stages, stages);
        }
      catch (const exception &error)
        {
          cerr << "Synthesis: " << error.what () <<endl;
          return 1;
        }
      DELETE (transform);
    }

  try
    {
      image2->write (outfile);
    }
  catch (const exception &error)
    {
      cerr << "Writing image: " << error.what () << endl;
      return 1;
    }

  DELETE (image1);
  DELETE (image2);

  return 0;
}

