/** @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.45 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2005-01-13 03:26:23 $
 *
 *  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 psU32 numCols;        ///< Number of columns in image
    const psU32 numRows;        ///< Number of rows in image.
    const psS32 col0;                    ///< Column position relative to parent.
    const psS32 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.

    psPtr rawDataBuffer;
}
psImage;

/** Basic image region structure.
 *
 * Struct for specifying a rectangular area in an image.
 *
 */
typedef struct
{
    psF32 x0;                         ///< the first column of the region.
    psF32 x1;                         ///< the last column of the region.
    psF32 y0;                         ///< the first row of the region.
    psF32 y1;                         ///< the last row of the region.
}
psRegion;

/** 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(
    psU32 numCols,                     ///< Number of rows in image.
    psU32 numRows,                     ///< Number of columns in image.
    const psElemType type              ///< Type of data for image.
);

/** Create a psRegion with the specified attributes.
 *
 * Uses psLib memory allocation functions to create a psRegion the
 * specified x0, x1, y0, and y1.
 *
 * @return psRegion* : Pointer to psRegion.
 *
 */
psRegion* psRegionAlloc(
    psF32 x0,                         ///< the first column of the region.
    psF32 x1,                         ///< the last column of the region.
    psF32 y0,                         ///< the first row of the region.
    psF32 y1                          ///< the last row of the region.
);

/** Create a psRegion with the attribute values given as a string.
 *
 *  Create a psRegion with the attribute values given as a string.  The format
 *  shall be of the standard IRAF form '[x0:x1,y0:y1]'
 *
 *  @return psRegion*:  A new psRegion struct, or NULL is not successful.
 */
psRegion* psRegionFromString(
    char* region                       ///< image rectangular region in the form '[x0:x1,y0:y1]'
);

/** Create a string of the standard IRAF form '[x0:x1,y0:y1]' from a psRegion.
 *
 *  @return char*:  A new string representing the psRegion as text, or NULL
 *                  is not successful.
 */
char* psRegionToString(
    psRegion* region                   ///< the psRegion to convert to a string
);

/** 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
    psU32 numCols,                     ///< the desired number of columns in image
    psU32 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 psS32      Number of children freed.
 *
 */
psS32 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
    psU32 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 */ \
        psU32 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 */ \
        psU32 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 */ \
        psU32 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 */ \
        psU32 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
