/*
 * class ImageArray
 *
 * $Date$
 * $Revision$
 *
 */

#ifndef IMAGE_ARRAY_HH__
#define IMAGE_ARRAY_HH__

class ColumnVector;

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

/**
 * A two-dimensional array wrapper. This allows us to access the image's
 * pixels or coefficients and provides some utility methods. It is the
 * main working horse for the Image framework.
 */ 
template<class T> class 
ImageArray
{
public:
  
  /** Constructor. Sets the dimension to zero. */
  ImageArray (void);
  /** Constructor. Sets the dimension and allocates space. A size of 
   * zero is allowed, negative values not.
   * @param rows
   * the vertical size
   * @param cols
   * the horizontal size */
  ImageArray (int rows, int cols);
  /** Destructor. Releases allocated memory. */
  virtual ~ImageArray (void);

  /** Returns the vertical size.
   * @return
   * the vertical size */
  inline int rows (void) const { return m_ysize; }
  /** Returns the horizontal size.
   * @return
   * the horizontal size */
  inline int cols (void) const { return m_xsize; }
  /** Returns the overall size (x*y).
   * @return
   * the overall size */
  inline int size (void) const { return m_xysize; }
  /** Returns the value at (x,y).
   * @param y
   * the row
   * @param x
   * the col
   * @return
   * the value */
  inline T at (int y, int x) const { return m_ar[abs (y, x)]; }

  /** Returns the array's {\em n}th value.
   * @param abs
   * the offset from the array start
   * @return
   * the value */
  virtual T at (int abs) const { return m_ar[abs]; }
  /** Sets the value at (x,y).
   * @param y
   * the row
   * @param x
   * the col
   * @param val
   * the value */
  inline void to (int y, int x, T val) { m_ar[abs (y, x)] = val; }
  /** Sets the array's {\em n}th value.
   * @param abs
   * the offset from the array start
   * @param val
   * the value */
  virtual void to (int abs, T val) { m_ar[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_rows[y] + x; }
  
  /** 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 */
  T smax (int fromY = 0, int fromX = 0, int toY = -1, int toX = -1) const;
  /** Returns the minimum 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 minimum */
  T smin (int fromY = 0, int fromX = 0, int toY = -1, int toX = -1) const;
  /** 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 */
  T amax (int fromY = 0, int fromX = 0, int toY = -1, int toX = -1) const;
  /** 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 */
  T amin (int fromY = 0, int fromX = 0, int toY = -1, int toX = -1) const;
  /** 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 */
  T saverage (int fromY = 0, int fromX = 0, int toY = -1, int toX = -1) const;
  
  /** 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 */
  T aaverage (int fromY = 0, int fromX = 0, int toY = -1, int toX = -1) const;

  /** Resize the array. The old values will be copied to the new
   * dimension as far as they fit in. 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);
  /** Import a raw array. The new dimensions and the new array will
   * be stored discarding the old ones.
   * @param rows
   * the new number of rows
   * @param cols
   * the new number of cols 
   * @param array
   * the new array */
  virtual void import (int rows, int cols, T *array);
  /** Create a copy. All values will be duplicated rather than the references.
   * @return
   * the new object */
  virtual ImageArray<T> *clone (void) const;
  /** Copy from a different array.
   * @param ia
   * the other array */
  virtual void copy (ImageArray<T> &ia);
  /** Copy from a different array.
   * @param ia
   * the other array */
  inline void copy (ImageArray<T> *ia) { copy (*ia); }
  /** Rough comparison. See if two arrays are similar according to a given
   * {\em epsilon} (important for floating-point comparisons).
   * @param ia
   * the other {\em ImageArray} object
   * @param epsilon
   * the epsilon
   * @return
   * if both are identical: {\em true}, else {\em false} */
  virtual bool epsilons (ImageArray<T> &ia, T epsilon) const;
  /** Rough comparison. See if two arrays are similar according to a given
   * {\em epsilon} (important for floating-point comparisons).
   * @param ia
   * the other {\em ImageArray} object
   * @param epsilon
   * the epsilon
   * @return
   * if both are identical: {\em true}, else {\em false} */
  inline bool epsilons (ImageArray<T> *ia, T epsilon) const 
  { return epsilons (*ia, epsilon); }
  /** Exact comparison. See if two arrays are similar.
   * @param ia
   * the other {\em ImageArray} object
   * @return
   * if both are identical: {\em true}, else {\em false} */
  inline bool equals (ImageArray<T> &ia) const { return epsilons (ia, (T)0); }
  
  /** Exact comparison. See if two arrays are similar.
   * @param ia
   * the other {\em ImageArray} object
   * @return
   * if both are identical: {\em true}, else {\em false} */
  inline bool equals (ImageArray<T> *ia) const { return equals (*ia); }

  /** Physical access to the array. This is dangerous but necessary for
   * performance reasons because we sometimes need to fill the array with
   * more than one value at a time.
   * @return
   * a reference to the array */
  inline T*& array (void) { return m_ar; }
  
protected:
  /** The array's horizontal size. */
  int m_xsize;
  /** The array's vertical size. */
  int m_ysize;
  /** The array's overall size (x*y). */
  int m_xysize;
  /** The actual array. */
  T *m_ar;
  /** An array holding all rows' offsets (optimizes addressing) */
  int *m_rows;
  /** Allocates and sets the `m_rows' member (e.g. after a resize or in 
   * the constructor). If `m_rows' is not NULL it will be deleted first */
  virtual void updateRowsArray (void);

}; /* class ImageArray */

#include "../ImageArray.cc"

/** @} */

#endif /* IMAGE_ARRAY_HH__ */

