/*
 * Implementation of class StillImage
 *
 * $Date$
 * $Revision$
 *
 */

#include "WImage/ImageArray.hh"
#include "WImage/StillImage.hh"
#ifndef _WIN32_WCE
#include "WImage/PgmReader.hh"
#include "WImage/RawReader.hh"
#endif
#ifdef PFI
#include "WImage/PfgReader.hh"
#include "WImage/PfgWriter.hh"
#endif
#ifndef _WIN32_WCE
#include "WImage/PgmWriter.hh"
#include "WImage/RawWriter.hh"
#endif
#include <stdexcept>
#include <cstring>
#include <cassert>
#ifndef _WIN32_WCE
#include <iostream>
#else
#include "WImage/miscdefs.h"
#endif

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

Image *
StillImage::mkImage (int rows, int cols) const
{
  //return NEW (StillImage (rows, cols));
  Image *ret = NEW (StillImage (rows, cols));
  //std::cout << "mkImage: " << ret << std::endl;
  return ret;
}

StillImage::StillImage (int rows, int cols): Image ()
{
  //cout << "StillImage: " << rows << " " << cols << endl;
  m_ysize = rows;
  m_xsize = cols;
  m_xysize = rows * cols;
  m_coeffs = NEW (ImageArray<coeff> (rows, cols));
  m_acol = NEW (ColumnVector (m_coeffs));
  m_arow = NEW (RowVector (m_coeffs));
  m_afull = NEW (FullVector (m_coeffs));
  m_asteps = m_ssteps = 0;
  m_coeffsMustDelete = true;
}

StillImage::StillImage (ImageArray<coeff> &ia): Image ()
{
  m_ysize = ia.rows ();
  m_xsize = ia.cols ();
  m_xysize = ia.size ();
  m_coeffs = ia.clone ();
  m_acol = NEW (ColumnVector (m_coeffs));
  m_arow = NEW (RowVector (m_coeffs));
  m_afull = NEW (FullVector (m_coeffs));
  m_asteps = m_ssteps = 0;
  m_coeffsMustDelete = true;
}

StillImage::~StillImage (void)
{
  if (m_coeffs != NULL && m_coeffsMustDelete)
    {
      DELETE (m_coeffs);
    }
  DELETENOTNULL (m_acol);
  DELETENOTNULL (m_arow);
  DELETENOTNULL (m_afull);
}

bool
StillImage::epsilons (Image &si, coeff epsilon) const
{
  return ((StillImage*)this)->m_coeffs->epsilons (((StillImage*)&si)->m_coeffs,
                                                  epsilon);
}

bool
StillImage::equals (Image &si) const
{
  return ((StillImage*)this)->m_coeffs->epsilons (((StillImage*)&si)->m_coeffs,
                                                  COEFF_EPSILON);
}

#ifndef _WIN32_WCE
void
StillImage::read (char const * fname, int rawy, int rawx)
{
  FileName fn (fname);
  read (fname, fn.guess (), rawy, rawx);
  m_acol->update ();
  m_arow->update ();
  m_afull->update ();
}

void
StillImage::read (char const * fname, filetype ftype, int rawy, int rawx)
{
  GreymapReader *ir = NULL;
  switch (ftype)
    {
    case fn_pgm:
      ir = NEW (PgmReader (fname, *m_coeffs));
      break;
    case fn_raw:
      if (rawy > 0 || rawx > 0)
        {
          ir = NEW (RawReader (fname, *m_coeffs, rawy, rawx));
        }
      else
        {
          ir = NEW (RawReader (fname, *m_coeffs));
        }
      break;
#ifdef PFI
    case fn_pfi:
      ir = NEW (PfgReader (fname, *m_coeffs));
      break;
#endif
    default:
      throw invalid_argument ("read: unknown file type.");
    }
  try
    {
      ir->read ();
      DELETE (ir);
    }
  catch (...)
    {
      DELETENOTNULL (ir);
      throw;
    }
  m_ysize = m_coeffs->rows ();
  m_xsize = m_coeffs->cols ();
  m_xysize = m_coeffs->size ();
}

void
StillImage::write (char const *fname, bool beautify)
{
  FileName fn (fname);
  write (fname, fn.guess (), beautify);
}

void
StillImage::write (char const *fname, filetype ftype, bool beautify)
{
  GreymapWriter *iw = NULL;
  bool ispixel = true;

  if (ftype == fn_unknown)
    {
      throw invalid_argument ("write: unknown file type.");
    }

  ImageArray<coeff> *tmp = m_coeffs->clone ();
  ImageArray<coeff> *backup = m_coeffs;
  m_coeffs = tmp;

  DELETE (m_acol);
  m_acol = NEW (ColumnVector (m_coeffs));

  DELETE (m_arow);
  m_arow = NEW (RowVector (m_coeffs));

  DELETE (m_afull);
  m_afull = NEW (FullVector (m_coeffs));

  switch (ftype)
    {
    case fn_pgm:
      iw = NEW (PgmWriter (fname, *m_coeffs));
      break;
    case fn_raw:
      iw = NEW (RawWriter (fname, *m_coeffs));
      break;
#ifdef PFI
    case fn_pfi:
      iw = NEW (PfgWriter (fname, *m_coeffs));
      ispixel = false;
      break;
#endif
    default:
      throw invalid_argument ("write: unknown file type.");
    }

  if (this->size () > 0 &&
      (beautify
       || (ispixel && (m_asteps - m_ssteps > 0 || (this->smin () < 0)))))
    {
      this->beautify ();
    }

  try
    {
      iw->write ();
      DELETE (iw);
    }
  catch (...)
    {
      DELETE (m_coeffs);
      m_coeffs = backup;

      DELETE (m_acol);
      m_acol = NEW (ColumnVector (m_coeffs));

      DELETE (m_arow);
      m_arow = NEW (RowVector (m_coeffs));

      DELETE (m_afull);
      m_afull = NEW (FullVector (m_coeffs));

      DELETENOTNULL (iw);
      throw;
    }

  DELETE (m_coeffs);
  m_coeffs = backup;

  DELETE (m_acol);
  m_acol = NEW (ColumnVector (m_coeffs));

  DELETE (m_arow);
  m_arow = NEW (RowVector (m_coeffs));

  DELETE (m_afull);
  m_afull = NEW (FullVector (m_coeffs));
}
#endif

Image *
StillImage::clone (void) const
{
  Image *ret = NEW (StillImage (*m_coeffs));
  ret->anasteps (this->m_asteps);
  ret->synsteps (this->m_ssteps);
  return ret;
}

void
StillImage::resize (int rows, int cols)
{
  if (rows == m_ysize && cols == m_xsize)
    {
      return;
    }
  m_ysize = rows;
  m_xsize = cols;
  m_xysize = rows * cols;
  m_coeffs->resize (rows, cols);
  m_acol->update ();
  m_arow->update ();
  m_afull->update ();
}

