/** @file  psImage.h
 *
 *  @brief Contains basic image definitions and operations
 *
 *  This file defines the basic type for an image struct and functions useful
 *  in manupulating images.
 *
 *  @ingroup Image
 *
 *  @author Robert DeSonia, MHPCC
 *  @author Ross Harman, MHPCC
 *
 *  @version $Revision: 1.41 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2004-10-14 01:22:59 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 */
#ifndef PS_IMAGE_H
#define PS_IMAGE_H

#include <complex.h>

#include "psType.h"
#include "psArray.h"

/// @addtogroup Image
/// @{

/** enumeration of options in interpolation
 *
 */
typedef enum {
    PS_INTERPOLATE_FLAT = 1,           ///< 'flat' interpolation (nearest pixel)
    PS_INTERPOLATE_BILINEAR,           ///< bi-linear interpolation
    PS_INTERPOLATE_BICUBIC,            ///< bi-cubic interpolation
    PS_INTERPOLATE_SINC,               ///< sinc interpolation
    PS_INTERPOLATE_NUM_MODES           ///< end-marker of list of modes; not a valid interpolation mode
} psImageInterpolateMode;

/** Basic image data structure.
 *
 * Struct for maintaining image data of varying types. It also contains
 * information about image size, parent images and children images.
 *
 */
typedef struct psImage
{
    const psType type;                 ///< Image data type and dimension.
    const unsigned int numCols;        ///< Number of columns in image
    const unsigned int numRows;        ///< Number of rows in image.
    const int col0;                    ///< Column position relative to parent.
    const int row0;                    ///< Row position relative to parent.

    union {
        psU8**  U8;                    ///< Unsigned 8-bit integer data.
        psU16** U16;                   ///< Unsigned 16-bit integer data.
        psU32** U32;                   ///< Unsigned 32-bit integer data.
        psU64** U64;                   ///< Unsigned 64-bit integer data.
        psS8**  S8;                    ///< Signed 8-bit integer data.
        psS16** S16;                   ///< Signed 16-bit integer data.
        psS32** S32;                   ///< Signed 32-bit integer data.
        psS64** S64;                   ///< Signed 64-bit integer data.
        psF32** F32;                   ///< Single-precision float data.
        psF64** F64;                   ///< Double-precision float data.
        psC32** C32;                   ///< Single-precision complex data.
        psC64** C64;                   ///< Double-precision complex data.
        psPTR** PTR;                   ///< Void pointers.
        psPTR*  V;                     ///< Pointer to data.
    } data;                            ///< Union for data types.
    const struct psImage* parent;      ///< Parent, if a subimage.
    psArray* children;                 ///< Children of this region.

    void* rawDataBuffer;
}
psImage;

/** Create an image of the specified size and type.
 *
 * Uses psLib memory allocation functions to create an image struct of the
 * specified size and type.
 *
 * @return psImage* : Pointer to psImage.
 *
 */
psImage* psImageAlloc(
    unsigned int numCols,              ///< Number of rows in image.
    unsigned int numRows,              ///< Number of columns in image.
    const psElemType type              ///< Type of data for image.
);

/** Resize a given image to the given size/type.
 *
 *  @return psImage* Resized psImage.
 *
 */
psImage* psImageRecycle(
    psImage* old,                      ///< the psImage to recycle by resizing image buffer
    unsigned int numCols,              ///< the desired number of columns in image
    unsigned int numRows,              ///< the desired number of rows in image
    const psElemType type              ///< the desired datatype of the image
);

/** Makes a copy of a psImage
 *
 * @return psImage* Copy of the input psImage.  This may not be equal to the
 * output parameter
 *
 */
psImage* psImageCopy(
    psImage* restrict output,          ///< if not NULL, a psImage that could be recycled.
    const psImage* input,              ///< the psImage to copy
    psElemType type                    ///< the desired datatype of the returned copy
);

/** Frees all children of a psImage.
 *
 *  @return int      Number of children freed.
 *
 */
int psImageFreeChildren(
    psImage* image                     ///< psImage in which all children shall be deallocated
);

/** Interpolate image pixel value given floating point coordinates.
 *
 *  @return psF32    Pixel value interpolated from image or unexposedValue if
 *                   given x,y doesn't coorespond to a valid image location
 */
psC64 psImagePixelInterpolate(
    const psImage* input,              ///< input image for interpolation
    float x,                           ///< column location to derive value of
    float y,                           ///< row location ot derive value of
    const psImage* mask,               ///< if not NULL, the mask of the input image
    unsigned int maskVal,              ///< the mask value
    psC64 unexposedValue,              ///< return value if x,y location is not in image.
    psImageInterpolateMode mode        ///< interpolation mode
);

#define p_psImagePixelInterpolateFcns(TYPE) \
inline psF64 p_psImagePixelInterpolateFLAT_##TYPE( \
        const psImage* input,          /**< input image for interpolation */ \
        float x,                       /**< column location to derive value of */ \
        float y,                       /**< row location ot derive value of */ \
        const psImage* mask,           /**< if not NULL, the mask of the input image */ \
        unsigned int maskVal,          /**< the mask value */ \
        psF64 unexposedValue           /**< return value if x,y location is not in image. */ \
                                                 ); \
inline psF64 p_psImagePixelInterpolateBILINEAR_##TYPE( \
        const psImage* input,          /**< input image for interpolation */ \
        float x,                       /**< column location to derive value of */ \
        float y,                       /**< row location ot derive value of */ \
        const psImage* mask,           /**< if not NULL, the mask of the input image */ \
        unsigned int maskVal,          /**< the mask value */ \
        psF64 unexposedValue           /**< return value if x,y location is not in image. */ \
                                                     );

#define p_psImagePixelInterpolateComplexFcns(TYPE) \
inline psC64 p_psImagePixelInterpolateFLAT_##TYPE( \
        const psImage* input,          /**< input image for interpolation */ \
        float x,                       /**< column location to derive value of */ \
        float y,                       /**< row location ot derive value of */ \
        const psImage* mask,           /**< if not NULL, the mask of the input image */ \
        unsigned int maskVal,          /**< the mask value */ \
        psC64 unexposedValue           /**< return value if x,y location is not in image. */ \
                                                 ); \
inline psC64 p_psImagePixelInterpolateBILINEAR_##TYPE( \
        const psImage* input,          /**< input image for interpolation */ \
        float x,                       /**< column location to derive value of */ \
        float y,                       /**< row location ot derive value of */ \
        const psImage* mask,           /**< if not NULL, the mask of the input image */ \
        unsigned int maskVal,          /**< the mask value */ \
        psC64 unexposedValue           /**< return value if x,y location is not in image. */ \
                                                     );

p_psImagePixelInterpolateFcns(U8)
p_psImagePixelInterpolateFcns(U16)
p_psImagePixelInterpolateFcns(U32)
p_psImagePixelInterpolateFcns(U64)
p_psImagePixelInterpolateFcns(S8)
p_psImagePixelInterpolateFcns(S16)
p_psImagePixelInterpolateFcns(S32)
p_psImagePixelInterpolateFcns(S64)
p_psImagePixelInterpolateFcns(F32)
p_psImagePixelInterpolateFcns(F64)
p_psImagePixelInterpolateComplexFcns(C32)
p_psImagePixelInterpolateComplexFcns(C64)

/// @}

#endif
