/** @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.51 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2005-04-29 02:25:10 $
 *
 *  Copyright 2004-2005 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,               ///< 'flat' interpolation (nearest pixel)
    PS_INTERPOLATE_BILINEAR,           ///< bi-linear interpolation
    PS_INTERPOLATE_LANCZOS2,           ///< Sinc interpolation with 4x4 pixel kernel
    PS_INTERPOLATE_LANCZOS3,           ///< Sinc interpolation with 6x6 pixel kernel
    PS_INTERPOLATE_LANCZOS4,           ///< Sinc interpolation with 8x8 pixel kernel
    PS_INTERPOLATE_BILINEAR_VARIANCE,  ///< Variance version of PS_INTERPOLATE_BILINEAR
    PS_INTERPOLATE_LANCZOS2_VARIANCE,  ///< Variance version of PS_INTERPOLATE_LANCZOS2
    PS_INTERPOLATE_LANCZOS3_VARIANCE,  ///< Variance version of PS_INTERPOLATE_LANCZOS3
    PS_INTERPOLATE_LANCZOS4_VARIANCE,  ///< Variance version of PS_INTERPOLATE_LANCZOS4
    PS_INTERPOLATE_NUM_MODES           ///< enum end-marker; does not coorespond to a 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* 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
);

bool p_psImageCopyToRawBuffer(
    void* buffer,
    const psImage* input,
    psElemType type
);

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

/** get an element of an image as a psF64.
 *
 *  @return psF64   pixel value at specified location
 */
psF64 p_psImageGetElementF64(
    psImage* image,                    ///< input image
    int col,                           ///< pixel column
    int row                            ///< pixel row
);

/** 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 PIXEL_INTERPOLATE_FCN_PROTOTYPE(SUFFIX, RETURNTYPE) \
inline RETURNTYPE p_psImagePixelInterpolate##SUFFIX( \
        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 */ \
        RETURNTYPE unexposedValue      /**< return value if x,y location is not in image. */ \
                                                   );

#define PIXEL_INTERPOLATE_FCNS(MODE) \
PIXEL_INTERPOLATE_FCN_PROTOTYPE(MODE##_U8,psF64)  \
PIXEL_INTERPOLATE_FCN_PROTOTYPE(MODE##_U16,psF64) \
PIXEL_INTERPOLATE_FCN_PROTOTYPE(MODE##_U32,psF64) \
PIXEL_INTERPOLATE_FCN_PROTOTYPE(MODE##_U64,psF64) \
PIXEL_INTERPOLATE_FCN_PROTOTYPE(MODE##_S8,psF64)  \
PIXEL_INTERPOLATE_FCN_PROTOTYPE(MODE##_S16,psF64) \
PIXEL_INTERPOLATE_FCN_PROTOTYPE(MODE##_S32,psF64) \
PIXEL_INTERPOLATE_FCN_PROTOTYPE(MODE##_S64,psF64) \
PIXEL_INTERPOLATE_FCN_PROTOTYPE(MODE##_F32,psF64) \
PIXEL_INTERPOLATE_FCN_PROTOTYPE(MODE##_F64,psF64) \
PIXEL_INTERPOLATE_FCN_PROTOTYPE(MODE##_C32,psC64) \
PIXEL_INTERPOLATE_FCN_PROTOTYPE(MODE##_C64,psC64)

#ifndef SWIG
PIXEL_INTERPOLATE_FCNS(FLAT)
PIXEL_INTERPOLATE_FCNS(BILINEAR)
PIXEL_INTERPOLATE_FCNS(BILINEAR_VARIANCE)
#endif // ! SWIG

#undef PIXEL_INTERPOLATE_FCN_PROTOTYPE
#undef PIXEL_INTERPOLATE_FCNS

/// @}

#endif // PS_IMAGE_H
