/* $Id: hdrl_bpm.c,v 1.1 2013-10-16 11:31:01 cgarcia Exp $
 *
 * This file is part of the HDRL
 * Copyright (C) 2013 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
 */

/*
 * $Author: cgarcia $
 * $Date: 2013-10-16 11:31:01 $
 * $Revision: 1.1 $
 * $Name: not supported by cvs2svn $
 */

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

/*-----------------------------------------------------------------------------
                                   Includes
-----------------------------------------------------------------------------*/

#include "hdrl_bpm.h"
#include <cpl.h>

/*-----------------------------------------------------------------------------
                                   Static
 -----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/**
  @defgroup hdrl_bpm   BPM Module
 */
/*----------------------------------------------------------------------------*/

/**@{*/

/* ---------------------------------------------------------------------------*/
/**
 * @brief convert bad pixel information mask to a cpl_mask
 *
 * @param bpm        integer image containing the bad pixel information
 * @param selection  bitmask selecting which values to set to bad
 *
 * @return cpl_mask
 * @note as cpl only supports 32 bit integer images the top 32 bit of the
 *       selection mask must be zero
 */
/* ---------------------------------------------------------------------------*/
cpl_mask * hdrl_bpm_to_mask(const cpl_image * bpm, uint64_t selection)
{
    cpl_ensure(bpm, CPL_ERROR_NULL_INPUT, NULL);
    cpl_ensure(cpl_image_get_type(bpm) == CPL_TYPE_INT,
               CPL_ERROR_ILLEGAL_INPUT, NULL);
    /* cpl currently only has int images, but use 64 for forward compat */
    cpl_ensure(selection <= CX_MAXUINT, CPL_ERROR_UNSUPPORTED_MODE, NULL);
    unsigned int iselection = (unsigned int)selection;
    const unsigned int * data = (unsigned int *)cpl_image_get_data_int_const(bpm);
    const size_t nx = cpl_image_get_size_x(bpm);
    const size_t ny = cpl_image_get_size_y(bpm);
    cpl_mask * msk = cpl_mask_new(nx, ny);
    cpl_binary * dmsk = cpl_mask_get_data(msk);

    for (size_t i = 0; i < ny * nx; i++) {
        dmsk[i] = (data[i] & iselection) ? 1 : 0;
    }

    return msk;
}


/* ---------------------------------------------------------------------------*/
/**
 * @brief convert cpl_mask to bad pixel information mask
 *
 * @param mask       cpl_mask to be converted
 * @param selection  bitmask selecting which values to set the bad pixels to
 *
 * @return integer cpl_image
 * @note as cpl only supports 32 bit integer images the top 32 bit of the
 *       selection mask must be zero
 */
/* ---------------------------------------------------------------------------*/
cpl_image * hdrl_mask_to_bpm(const cpl_mask * mask, uint64_t flag)
{
    cpl_ensure(mask, CPL_ERROR_NULL_INPUT, NULL);
    /* cpl currently only has int images, but use 64 for forward compat */
    cpl_ensure(flag <= CX_MAXUINT, CPL_ERROR_UNSUPPORTED_MODE, NULL);
    unsigned int iflag = (unsigned int)flag;
    const size_t nx = cpl_mask_get_size_x(mask);
    const size_t ny = cpl_mask_get_size_y(mask);
    cpl_image * bpm = cpl_image_new(nx, ny, CPL_TYPE_INT);
    const cpl_binary * dmsk = cpl_mask_get_data_const(mask);
    unsigned int * data = (unsigned int *)cpl_image_get_data_int(bpm);

    for (size_t i = 0; i < ny * nx; i++) {
        data[i] = dmsk[i] ? iflag : 0;
    }

    return bpm;
}


/* ---------------------------------------------------------------------------*/
/**
 * @brief apply array of masks to an imagelist
 *
 * @param list  imagelist where the masks shoudl be applied
 * @param masks array of masks, must have same length as imagelist
 *
 * already existing masks will be overwritten
 * can be used to reapply the original mask array returned by
 * hdrl_join_mask_on_imagelist
 *
 * example:
 * cpl_mask ** orig_masks;
 * // change mask to get partial statistics from the list
 * hdrl_join_mask_on_imagelist(list, echelle_mask, &orig_masks);
 * stats = get_stats_from_echelle_orders()
 * // restore original mask
 * hdrl_set_masks_on_imagelist(list, orig_masks);
 * // free memory
 * for (i = 0; i < cpl_imagelist_get_size(list); i++) {
 *   cpl_mask_free(orig_masks[i]);
 * }
 * cpl_free(orig_masks);
 */
/* ---------------------------------------------------------------------------*/
cpl_error_code
hdrl_set_masks_on_imagelist(cpl_imagelist * list, cpl_mask ** masks)
{
    cpl_ensure_code(list, CPL_ERROR_NULL_INPUT);
    cpl_ensure_code(masks, CPL_ERROR_NULL_INPUT);

    for (size_t i = 0; i < (size_t)cpl_imagelist_get_size(list); i++) {
        cpl_image * img = cpl_imagelist_get(list, i);
        cpl_mask * img_mask = cpl_image_get_bpm(img);
        /* zero mask */
        cpl_mask_xor(img_mask, img_mask);
        /* add new mask */
        cpl_mask_or(img_mask, masks[i]);
    }

    return cpl_error_get_code();
}


/* ---------------------------------------------------------------------------*/
/**
 * @brief join mask with existing masks in an imagelist
 *
 * @param list      imagelist where the new mask should be joined on
 * @param new_mask  new mask joined with the masks in the images
 * @param pold_mask pointer to array pointer to store a copy of the original
 *                  masks, array and masks contained in it must be deleted by
 *                  the user, may be NULL in which case no copy is stored
 * @see hdrl_set_masks_on_imagelist
 */
/* ---------------------------------------------------------------------------*/
cpl_error_code
hdrl_join_mask_on_imagelist(cpl_imagelist * list, cpl_mask * new_mask,
                            cpl_mask *** pold_mask)
{
    cpl_ensure_code(list, CPL_ERROR_NULL_INPUT);
    cpl_ensure_code(new_mask, CPL_ERROR_NULL_INPUT);

    if (pold_mask) {
        *pold_mask = cpl_malloc(sizeof(*pold_mask) *
                                cpl_imagelist_get_size(list));
    }

    for (size_t i = 0; i < (size_t)cpl_imagelist_get_size(list); i++) {
        cpl_image * img = cpl_imagelist_get(list, i);
        cpl_mask * img_mask = cpl_image_get_bpm(img);
        if (pold_mask) {
            (*pold_mask)[i] = cpl_mask_duplicate(img_mask);
        }

        cpl_mask_or(img_mask, new_mask);
    }

    return cpl_error_get_code();
}

/**@}*/
