/*
 * class StillImage
 *
 * $Date$
 * $Revision$
 *
 */

#ifndef STILL_IMAGE_HH__
#define STILL_IMAGE_HH__

#include "WImage/Image.hh"

/** 
 * @addtogroup WImage 
 * @{ */

/**
 * A still image. A (grey-scale) two-dimensional image.
 */
class 
StillImage: public Image
{
public:
  
  /** Constructor. Creates an empty image with given dimensions.
   * @param rows
   * the number of rows
   * @param cols
   * the number of cols */
  StillImage (int rows = 0, int cols = 0);
  /** Constructor. Imports an existing {\em ImageArray} object. The 
   * array will be duplicated.
   * @param ia
   * The source array */
  StillImage (ImageArray<coeff> &ia);
  /** Destructor. Deallocates objects. */
  virtual ~StillImage (void);

  /** Get a value. Returns the value at row {\em y} and col {\em x}.
   * @param y
   * the row
   * @param x
   * the col
   * @return 
   * the value */
  virtual coeff at (int y, int x) const { return m_coeffs->at (y, x); }
  /** Get a value. Returns the value at absolute position {\em abs}.
   * @param abs
   * the position
   * @return 
   * the value */
  virtual coeff at (int abs) const { return m_coeffs->at (abs); }
  /** Set a value. Sets the value at row {\em y} and col {\em x}.
   * @param y
   * the row
   * @param x
   * the col
   * @param val
   * the new value
   * @return 
   * the value */
  virtual void to (int y, int x, coeff val) { m_coeffs->to (y, x, val); }
  /** Set a value. Sets the value at absolute position {\em abs}.
   * @param abs
   * the position
   * @param val
   * the new value */
  virtual void to (int abs, coeff val) { m_coeffs->to (abs, val); }

  /** Return the absolute offset of a position.
   * @param y
   * the position's row
   * @param x
   * the position's col
   * @return
   * the absolute offset */
  virtual int abs (int y, int x) const { return m_coeffs->abs (y, x); }
  
  /** Rough comparison. See if two images are similar according to a given
   * {\em epsilon} (important for floating-point comparisons).
   * @param si
   * the other {\em Image} object
   * @param epsilon
   * the epsilon
   * @return
   * if both are identical: {\em true}, else {\em false} */
  virtual bool epsilons (Image &si, coeff epsilon) const;
  /** Compares two still images. Return {\em true} if both are equal.
   * @param si
   * The other {\em StillImage} object
   * @return 
   * if equals: {\em true}, else {\em false} */
  virtual bool equals (Image &si) const;

#ifndef _WIN32_WCE
  /** Read an image. Reads an image from a file guessing the file type
   * from the file name's extension. Currently PGM, RAW and PFI are
   * supported.
   * @exception invalid_argument
   * the file type is either not supported or could not be determined
   * from the given file name
   * @param fname
   * the file name, if {\em NULL}, then {\em stdin}
   * @param rawy
   * the number of rows (only needed for RAW format)
   * @param rawx
   * the number of cols (only needed for RAW format) */
  virtual void read (char const *fname, int rawy = 0, int rawx = 0);
  /** Read an image. Reads an image from a file using the specified 
   * file type. Currently PGM, RAW and PFI are supported.
   * @exception invalid_argument
   * the file type is either not supported or could not be determined
   * from the given file name
   * @param fname
   * the file name, if {\em NULL}, then {\em stdin}
   * @param ftype
   * the file type
   * @param rawy
   * the number of rows (only needed for RAW format)
   * @param rawx
   * the number of cols (only needed for RAW format) */
  virtual void read (char const *fname, 
                     filetype ftype, int rawy = 0, int rawx = 0);

  /** Write an image (abstract). Writes an image to a file guessing the 
   * file type from the file name's extension.
   * @param fname
   * the file name, if {\em NULL}, then {\em stdout} 
   * @param beautify
   * beautify images that have not had more analysis than synthesis steps? */
  virtual void write (char const *fname, bool beautify = false);
  /** Write an image (abstract). Writes an image to a file using the 
   * specified file type.
   * @param ftype
   * the file type
   * @param fname
   * the file name, if {\em NULL}, then {\em stdout} 
   * @param beautify
   * beautify images that have not had more analysis than synthesis steps? */
  virtual void write (char const *fname, filetype ftype, 
                      bool beautify = false);
#endif

  /** Produce a copy. Every dynamically object will be cloned rather than
   * passing on the reference.
   * @return
   * the new, copied object. */
  virtual Image *clone (void) const;

  /** Create an empty StillImage.
   * @param rows the number of rows
   * @param cols the number of cols
   * @return the new image
   */
  inline static Image *makeEmpty (int rows = 0, int cols = 0) 
  { return new StillImage (rows, cols); }

  /** Returns the maximum value in a region. Signs will be considered. 
   * @param fromY the first point's row
   * @param fromX the first point's col
   * @param toY the second point's row (-1 if lower image border)
   * @param toX the second point's col (-1 if right image border)
   * @return
   * the maximum */
  virtual coeff smax (int fromY = 0, int fromX = 0,
                      int toY = -1, int toX = -1) const { 
    return m_coeffs->smax (fromY, fromX, toY, toX); 
  }
  /** Returns the maximum absolute value in a region. Signs will be discarded.
   * @param fromY the first point's row
   * @param fromX the first point's col
   * @param toY the second point's row (-1 if lower image border)
   * @param toX the second point's col (-1 if right image border)
   * @return
   * the maximum */
  virtual coeff smin (int fromY = 0, int fromX = 0,
                      int toY = -1, int toX = -1) const { 
    return m_coeffs->smin (fromY, fromX, toY, toX); 
  }
  /** Returns the maximum absolute value in a region. Signs will be discarded.
   * @param fromY the first point's row
   * @param fromX the first point's col
   * @param toY the second point's row (-1 if lower image border)
   * @param toX the second point's col (-1 if right image border)
   * @return
   * the maximum */
  virtual coeff amax (int fromY = 0, int fromX = 0,
                      int toY = -1, int toX = -1) const { 
    return m_coeffs->amax (fromY, fromX, toY, toX); 
  }
  /** Returns the minimum absolute value in a region. Signs will be discarded.
   * @param fromY the first point's row
   * @param fromX the first point's col
   * @param toY the second point's row (-1 if lower image border)
   * @param toX the second point's col (-1 if right image border)
   * @return
   * the minimum */
  virtual coeff amin (int fromY = 0, int fromX = 0,
                      int toY = -1, int toX = -1) const { 
    return m_coeffs->amin (fromY, fromX, toY, toX); 
  }
  /** Return the average color for a rectangular region inside the image
   * drawn from one point within and the second point just outside the
   * region. The coefficients' signedness will be considered.
   * @param fromY the first point's row
   * @param fromX the first point's col
   * @param toY the second point's row (-1 if lower image border)
   * @param toX the second point's col (-1 if right image border)
   * @return the average color */
  virtual coeff saverage (int fromY = 0, int fromX = 0, 
                          int toY = -1, int toX = -1) const { 
    return m_coeffs->saverage (fromY, fromX, toY, toX); }

  /** Return the average color for a rectangular region inside the image
   * drawn from one point within and the second point just outside the
   * region. The coefficients' signedness will be discarded.
   * @param fromY the first point's row
   * @param fromX the first point's col
   * @param toY the second point's row (-1 if lower image border)
   * @param toX the second point's col (-1 if right image border)
   * @return the average color */
  virtual coeff aaverage (int fromY = 0, int fromX = 0, 
                          int toY = -1, int toX = -1) const { 
    return m_coeffs->aaverage (fromY, fromX, toY, toX); }

  /** Resize the image's x/y dimensions. The old values will remain
   * as far as they fit in the new dimensions. The new dimensions must 
   * all be greater than zero.
   * @exception invalid_argument
   * one or both dimensions are either negative or zero
   * @param rows
   * the new number of rows
   * @param cols
   * the new number of cols */
  virtual void resize (int rows, int cols);

#ifdef USE_DEPRECATED_API
  /** Rough comparison. See if two images are similar according to a given
   * {\em epsilon} (important for floating-point comparisons).
   * @param si
   * the other {\em Image} object
   * @param epsilon
   * the epsilon
   * @return
   * if both are identical: {\em true}, else {\em false} */
  inline bool epsilons (StillImage *si, coeff epsilon) const 
  { return Image::epsilons (si, epsilon); }
  /** Compares two still images. */
  inline bool equals (StillImage *si) const { return Image::equals (si); }
#endif

protected:
  /** Dummy constructor, only to be called by derived classes. 
   * @param dummy only distinguishes this constructor from the others */
  StillImage (bool dummy) {}
  /** The image values. The image values are stored in a two-dimensional
   * array. */
  ImageArray<coeff> *m_coeffs;

  /** This is true if the `m_coeffs' member variable is private to the object
   * and must therefore be deleted at object destruction */
  bool m_coeffsMustDelete;

  /** Factory method to get a new instance of a given size 
   * filled with zeroes.
   * @param rows
   * the number of rows
   * @param cols
   * the number of cols 
   * @return the new image */
  virtual Image *mkImage (int rows = 0, int cols = 0) const;
}; /* class StillImage */

/** @} */

#endif /* STILL_IMAGE_HH__ */

