/*
 * class ImageInformation
 *
 * $Date$
 * $Revision$
 *
 */

#ifndef IMAGE_INFORMATION_HH__
#define IMAGE_INFORMATION_HH__

#include "WImage/CoeffInformation.hh"
#include "WImage/Image.hh"

/**
 * @addtogroup WTools
 * @{ */
/** A comparison function type for coefficients. Different criterions
 * (e.g. value or index) can be used. */
typedef
bool (*cipredicate) (const CoeffInformation *c1, const CoeffInformation *c2);

#define PII_YPOS(info,pos)  (((info)->at (pos)).ypos ())
#define PII_XPOS(info,pos)  (((info)->at (pos)).xpos ())
#define PII_XYPOS(info,pos) (((info)->at (pos)).xypos ())
#define II_YPOS(info,pos)   (((info).at (pos)).ypos ())
#define II_XPOS(info,pos)   (((info).at (pos)).xpos ())
#define II_XYPOS(info,pos)  (((info).at (pos)).xypos ())

/**
 * Image information. The information consists coefficient information
 * nodes, so the original image can be reconstructed from this. Tool
 * methods for sorting, shuffleing etc. are used for watermark.
 */
class
ImageInformation
{
public:
  /** Constructor. Initializes a number of empty components.
   * @param size the number of components */
  ImageInformation (int size = 0);
  /** Constructor. Gets information from an image.
   * @param img
   * the source image */
  ImageInformation (Image &img);
  /** Destructor. Frees allocated objects. */
  ~ImageInformation (void);
  /** Get the number of stored coeffs.
   * @return
   * the number of stored coeffs */
  inline int size (void) const { return m_size; }
  /** Get the first n coeffs.
   * @param n
   * the number of coeffs
   * @return
   * a new info object containing the coeffs */
  ImageInformation *head (int n);
  /** Get the last n coeffs.
   * @param n
   * the number of coeffs
   * @return
   * a new info object containing the coeffs */
  ImageInformation *tail (int n);
  /** Append another ImageInformation object.
   * @param ii
   * the other ImageInformation object.
   * @return
   * a new info object containing the coeffs */
  ImageInformation *append (ImageInformation &ii);
  /** Get a copy of this.
   * @return
   * a new info object containing a copy of this */
  inline ImageInformation *clone (void) {
    return head (m_size);
    //ImageInformation *ret = new ImageInformation (0);
    //ret->m_coeffs = new CoeffInformation [m_size];
    //ret->m_size = m_size;
    //for (int i = 0; i < m_size; i++)
    //  {
    //    ret->m_coeffs[i] = m_coeffs[i];
    //  }
    //return ret;
  }
  /** Shrink (discard some of the coeffs).
   * @param newsize
   * the new number of coeffs, if greater than the actual size, the
   * operation has no effect
   * @param leavehead
   * if {\em true} discard from behind, else discard from the top */
  void shrink (int newsize, bool leavehead = true);
  /** Equality test.
   * @param ii
   * other info object
   * @return
   * if number of coeffs, order and the coeffs themselves
   * are equal: {\em true}, else {\em false} */
  bool equals (ImageInformation &ii);
  /** Return a coeff info.
   * @param pos
   * the info's position in this object (array index)
   * @return
   * a reference to the coeff info node */
  inline CoeffInformation &at (int pos) { return m_coeffs[pos]; }
  /** Set a position from a CoeffInformation object.
   * @param c
   * the CoeffInformation object
   * @param pos
   * the info's position in this object (array index) */
  inline void to (CoeffInformation &c, int pos) { m_coeffs[pos] = c; }
  /** Set a position from a CoeffInformation object.
   * @param c
   * the CoeffInformation object
   * @param pos
   * the info's position in this object (array index) */
  inline void to (const CoeffInformation &c, int pos) { m_coeffs[pos] = c; }
  /** Resize the object preserving as many old values as possible.
   * @param size the new size */
  void resize (int size);
  /** Swap two coefficients.
   * @param pos1
   * the first object's position
   * @param pos2
   * the second object's position */
  void swap (int pos1, int pos2);

  /** Sort the coeffs according to their values.
   * @param isless
   * the comparison function to use. */
  void gensort (cipredicate isless);
  /** Sort the coeffs according to their values. */
  void ssort (void);
  /** Sort the coeffs according to their absolute values. */
  void asort (void);
  /** Sort the coeffs according to their absolute positions in the image. */
  void psort (void);
  /** Sort the coeffs according to their rows/cols positions in the image. */
  void yxsort (void);
  /** Sort the coeffs according to their cols/rows positions in the image. */
  void xysort (void);
  /** Sort the coeffs according to their IDs. */
  void isort (void);
  /** Mix coeffs using pseudo-random numbers. */
  void shuffle (void);
  /** Are the coeffs sorted according to their values?
   * @return
   * if sorted according to their values: {\em true}, else {\em false} */
  bool ssorted (void) const;
  /** Are the coeffs sorted according to their absolute values?
   * @return
   * if sorted according to their values: {\em true}, else {\em false} */
  bool asorted (void) const;
  /** Are the coeffs sorted according to their position in their image?
   * @return
   * if sorted according to their positions: {\em true}, else {\em false} */
  bool psorted (void) const;
  /** Are the coeffs sorted according to their IDs?
   * @return
   * if sorted according to their IDs: {\em true}, else {\em false} */
  bool isorted (void) const;
  /** Returns true if a position is in this ImageInformation object.
   * @param abs the absolute position in the image
   * @return true if the position was found */
  inline bool isIn (int abs) const { return locate (abs) >= 0; }
  /** Returns true if a position is in this ImageInformation object.
   * @param y the row in the image
   * @param x the col in the image
   * @return true if the position was found */
  inline bool isIn (int y, int x) const { return locate (y, x) >= 0; }
  /** Returns true a position's index if it is is in this
   * ImageInformation object.
   * @param abs the absolute position in the image
   * @return the index if found, else -1 */
  int locate (int abs) const;
  /** Returns true a position's index if it is is in this
   * ImageInformation object.
   * @param y the row in the image
   * @param x the col in the image
   * @return the index if found, else -1 */
  int locate (int y, int x) const;
  /** Get the maximum signed value from the selected coefficients.
   * @return
   * the maximum value */
  coeff amax (void);
  /** Get the maximum absolute value from the selected coefficients.
   * @return
   * the maximum value */
  coeff smax (void);
  /** Get the minimum absolute value from the selected coefficients.
   * @return
   * the minimum value */
  coeff amin (void);
  /** Get the minimum signed value from the selected coefficients.
   * @return
   * the minimum value */
  coeff smin (void);

#ifndef _WIN32_WCE
  /** Write the contents to stdout or a file.
   * @exception ios_base::failure if the file could not be opened for writing.
   * @param delim what to print between two entries
   * @param file the name of the file (empty string for stdout) */
  void dump (const char *delim = " ", const char *file = "") const;
#endif

  /** Return the average absolute greyscale value.
   * @return the average absolute greyscale value */
  coeff aaverage (void) const;

  /** Return the average (signed) greyscale value.
   * @return the average greyscale value */
  coeff saverage (void) const;

  /** Return the square variance.
   * @return the square variance */
  double sqvariance (void) const;

  /** Return the variance.
   * @param abs true if signs are discarded.
   * @return the variance */
  double variance (bool abs = false) const;

  /** Returns the standard deviation.
   * @param abs true if signs are discarded.
   * @return the standard deviation. */
  double sdeviation (bool abs = false) const;

#ifdef USE_DEPRECATED_API
  /** Equality test.
   * @param ii
   * other info object
   * @return
   * if number of coeffs, order and the coeffs themselves
   * are equal: {\em true}, else {\em false} */
  inline bool equals (ImageInformation *ii) { return equals (*ii); }
#endif
protected:
  /** An array containing the coefficient nodes. */
  CoeffInformation *m_coeffs;
  /** The number of coeffs. */
  int m_size;
  /** Obtain a subset of the coeffs.
   * @param coeffs
   * the address of the CoeffInformation array to write to
   * @param size
   * the new array's size
   * @param head
   * if {\em true} the subset will be taken from the top, else from
   * the bottom */
  void copyCoeffs (CoeffInformation *coeffs, int size, bool head);
  /** Obtain a new info object containging a subset of the coeffs.
   * @param size
   * the number of coeffs to be stored
   * @param head
   * if {\em true} the subset will be taken from the top, else from
   * the bottom
   * @return
   * the new info object */
  ImageInformation *subimage (int size, bool head);
  /** Obtain positive pseudo-random numbers.
   * @param from
   * the minimum number
   * @param to
   * one more than the maximum number
   * @return
   * the pseudo-random number */
  int randint (int from, int to);
  /** Sort the coefficients. A Quicksort algorithm according to
   * Jon Bentley.
   * @param from
   * the start index
   * @param to
   * the end index (included in sort)
   * @param isless
   * the the comparison function, {\em true} when the left arg is
   * less than the right one */
  void quicksort (int from, int to, cipredicate isless);

}; /* class ImageInformation */

/** @} */

#endif /* IMAGE_INFORMATION_HH__ */

