/*
 * This file is part of the GIRAFFE Pipeline
 * Copyright (C) 2002-2019 European Southern Observatory
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <cxmemory.h>

#include "giimagestack.h"


/**
 * @defgroup giimagestack Image Stack
 *
 * TBD
 */

/**@{*/

/**
 * @brief
 *   Create a new GiImageStack
 *
 * @param size  Number of images for which to allocate room for
 *
 * @return Pointer to newly created @em GiImageStack or NULL if an error
 *         occured
 *
 * Creates a new GiImageStack with memory allocated for @a size images
 */

GiImageStack*
giraffe_imagestack_new(cxint size)
{

    GiImageStack *istack = NULL;

    istack = cx_malloc(sizeof(GiImageStack));

    istack->nimages = size;
    istack->images  = cx_calloc(size, sizeof(cpl_image *));

    return istack;

}


/**
 * @brief
 *   Non destructive resize of an GiImageStack
 *
 * @param istack   GiImageStack to resize
 * @param size     New size
 *
 * @return ==0 if succesful, >0 if an error occurred
 *
 * Resizes an GiImageStack. In case the new GiImageStack is larger in size
 * than the original GiImageStack, the GiImageStack is grown. All new
 * GiImageStack entries are initialized to NULL.
 * In case the new GiImageStack is smaller than the original, the
 * GiImageStack is shrunk. All superfluous elements are properly disposed
 * off, by calling the destructor for each of them.
 */

cxint
giraffe_imagestack_resize(GiImageStack *istack, cxint size)
{

    cxint i;

    cpl_image **tmp = NULL;


    if (istack == NULL) {
        return 1;
    }

    if (istack->nimages == size) {
        return 0;
    }

    tmp = cx_calloc(size, sizeof(cpl_image *));

    if (size > istack->nimages) {
        /* grow array */
        for (i = 0; i < istack->nimages; ++i) {
            tmp[i] = istack->images[i];
        }

        for (i = istack->nimages; i < size; ++i) {
            tmp[i] = NULL;
        }
    }
    else {
        /* shrink array */
        for (i = 0; i < size; ++i) {
            tmp[i] = istack->images[i];
        }

        for (i = size; i < istack->nimages; ++i) {
            cpl_image_delete(istack->images[i]);
        }
    }

    cx_free(istack->images);

    istack->images = tmp;

    return 0;

}


/**
 * @brief
 *   Destroys an GiImageStack
 *
 * @param istack  GiImageStack to destroy
 *
 * Destroys the GiImageStack @a istack and frees all associated memory
 */

void
giraffe_imagestack_delete(GiImageStack *istack)
{

    cxint i;

    if (istack == NULL) {
        return;
    }

    if (istack->images != NULL) {
        for (i = 0; i < istack->nimages; ++i) {
            cpl_image_delete(istack->images[i]);
        }

        cx_free(istack->images);
    }

    istack->images = NULL;
    istack->nimages = 0;

    return;

}


/**
 * @brief
 *   Stores a reference to a cpl_image in a GiImageStack
 *
 * @param istack    GiImageStack to store the reference to the image in
 * @param position  Position at which to store the reference
 * @param src       Image to which reference should point
 *
 * @return
 *   0 if succesful, or a positive number if an error occurred.
 *
 * Stores a reference i.e. a pointer to the cpl_image @a src in the
 * @em GiImageStack @a istack at position @a position.
 *
 * @note
 *   In case a @a cpl_image is already stored at the position @a position
 *   make sure you have another reference to this image so you will still
 *   be able to access it. This function can not check whether you have one
 *   and will simply store the new reference, thereby making the image
 *   potentially unreachable (memory leak).
 */

cxint
giraffe_imagestack_set(GiImageStack *istack, cxint position, cpl_image *src)
{
    if (istack == NULL) {
        return 1;
    }

    if (istack->images == NULL) {
        return 1;
    }

    if ((position < 0) || (position > istack->nimages)) {
        return 2;
    }

    istack->images[position] = src;

    return 0;

}


/**
 * @brief
 *   Retrieve a cpl_image reference stored in a GiImageStack
 *
 * @param istack    GiImageStack from which to retrieve the reference
 * @param position  Position of the reference
 *
 * @return Pointer to a @em cpl_image if succesful, or NULL if an error
 *         occurred
 *
 * Function returns the reference i.e. pointer contained in the GiImageStack
 * @a istack at position @em position and returns it.
 */

cpl_image *
giraffe_imagestack_get(GiImageStack *istack, cxint position)
{

    if (istack == NULL) {
        return NULL;
    }

    if (istack->images == NULL) {
        return NULL;
    }

    if ((position < 0) || (position > istack->nimages)) {
        return NULL;
    }

    return istack->images[position];

}


/**
 * @brief
 *   Returns current size of an GiImageStack
 *
 * @param istack  GiImageStack for which to return the size
 *
 * @return Maximum number of cpl_image pointers to store in GiImageStack
 *         or 0 if an error occured.
 *
 * Returns the current size of the GiImageStack @a istack i.e. how many
 * references to a cpl_image are stored/can be stored in it.
 */

cxint
giraffe_imagestack_size(GiImageStack *istack)
{

    if (istack == NULL) {
        return 0;
    }

    return istack->nimages;

}
/**@}*/
