/*                                                                              *
 *   This file is part of the ESO VISIR package                                 *
 *   Copyright (C) 2004,2005 European Southern Observatory                      *
 *                                                                              *
 *   This library 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, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA       *
 *                                                                              */
 
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

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

#include <visir_inputs.h>

#include "visir_inputs.c"
/* for unlink */
#include <unistd.h>

/*-----------------------------------------------------------------------------
                                Defines
 -----------------------------------------------------------------------------*/

#ifndef BOX_SIZE
#define BOX_SIZE 11
#endif

#ifndef LINE_SIZE
#define LINE_SIZE BOX_SIZE
#endif

#define TEST_LIST(list, value) \
do { \
    for (int i = 0; i < cpl_imagelist_get_size((list)); i++) { \
        int b; \
        const cpl_image * image = cpl_imagelist_get_const((list), i); \
        cpl_test_eq((value), cpl_image_get(image, 1, 1, &b)); \
    } \
} \
while(0)

#define A_VAL 4.
#define B_VAL 3.

/*-----------------------------------------------------------------------------
                         Declarations of private functions
 -----------------------------------------------------------------------------*/

static void visir_img_check_box_test(void);
static void visir_img_check_align_test(void);
static void visir_img_check_line_test(void);
static void visir_check_get_type(void);
static void visir_img_check_burst_find_delta_chop(void);
static void visir_img_check_load_burst(void);
static void visir_img_check_get_to_off_plane(void);
static void visir_img_check_load_cube2(void);

static cpl_propertylist * create_property_list(const char *,
                                               const char *,
                                               const double,
                                               const double,
                                               const double);
static cpl_imagelist * create_cube2_imagelist(int);
static cpl_imagelist * create_input_imagelist(const int *, int);


/*----------------------------------------------------------------------------*/
/**
 * @defgroup visir_inputs_test Testing of the VISIR utilities
 */
/*----------------------------------------------------------------------------*/


/*----------------------------------------------------------------------------*/
/**
   @brief   Unit tests of inputs module
**/
/*----------------------------------------------------------------------------*/
int main(void)
{

    cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_WARNING);

    visir_img_check_line_test();
    visir_img_check_align_test();
    visir_img_check_box_test();
    visir_check_get_type();
    visir_img_check_burst_find_delta_chop();
    visir_img_check_load_burst();
    visir_img_check_get_to_off_plane();
    visir_img_check_load_cube2();

    return cpl_test_end(0);

}

/* FIXME: Write a short doxygen of each static function */

static void visir_img_check_box_test(void)
{

    cpl_image     * image;
    const double    sigma = 1.0;
    cpl_apertures * appos;
    cpl_apertures * apneg;
    double          ecc;
    cpl_boolean     swapp, swapn;
    FILE          * stream;
    cpl_error_code  error = CPL_ERROR_NONE;
    int i, j;

    stream = cpl_msg_get_level() > CPL_MSG_INFO
        ? fopen("/dev/null", "a") : stdout;

    cpl_test_nonnull( stream );

    image = cpl_image_new(3 * BOX_SIZE, 3 * BOX_SIZE, CPL_TYPE_INT);

    /* Create four 3x3-pixel objects */
    for (j = -1; j <= 1; j++) {
      for (i = -1; i <= 1; i++) {
          error |= cpl_image_set(image,   BOX_SIZE + i,   BOX_SIZE + j, -1.0);
          error |= cpl_image_set(image, 2*BOX_SIZE + i, 2*BOX_SIZE + j, -1.0);
          error |= cpl_image_set(image,   BOX_SIZE + i, 2*BOX_SIZE + j,  1.0);
          error |= cpl_image_set(image, 2*BOX_SIZE + i,   BOX_SIZE + j,  1.0);
          cpl_test_eq_error(error, CPL_ERROR_NONE);
      }
    }

    appos = cpl_apertures_extract_sigma(image, sigma);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_nonnull(appos);
    cpl_test_eq(cpl_apertures_get_size(appos), 2);

    cpl_apertures_dump(appos, stream);

    error = cpl_image_multiply_scalar(image, -1.0);
    cpl_test_eq_error(error, CPL_ERROR_NONE);

    apneg = cpl_apertures_extract_sigma(image, sigma);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_nonnull(apneg);
    cpl_test_eq(cpl_apertures_get_size(apneg), 2);

    cpl_apertures_dump(apneg, stream);

    /* Various error checks */
    ecc = visir_img_check_box(NULL, 1, 2, apneg, 1, 2, BOX_SIZE, 0.,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    ecc = visir_img_check_box(appos, 1, 2, NULL, 1, 2, BOX_SIZE, 0.,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    ecc = visir_img_check_box(appos, 1, 2, apneg, 1, 2, BOX_SIZE, 0.,
                              &swapp, NULL);
    cpl_test_error(CPL_ERROR_UNSPECIFIED);

    ecc = visir_img_check_box(appos, 1, 2, apneg, 1, 2, BOX_SIZE, 0.,
                              NULL, &swapn);
    cpl_test_error(CPL_ERROR_UNSPECIFIED);

    ecc = visir_img_check_box(appos, 1, 2, appos, 1, 2, BOX_SIZE, 0.,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_UNSPECIFIED);

    ecc = visir_img_check_box(appos, 0, 2, apneg, 1, 2, BOX_SIZE, 0.,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    ecc = visir_img_check_box(appos, 1, 2, apneg, 1, 0, BOX_SIZE, 0.,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    ecc = visir_img_check_box(appos, 1, 2, apneg, 1, 3, BOX_SIZE, 0.,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_ACCESS_OUT_OF_RANGE);

    ecc = visir_img_check_box(appos, 3, 2, apneg, 1, 2, BOX_SIZE, 0.,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_ACCESS_OUT_OF_RANGE);

    ecc = visir_img_check_box(appos, 1, 2, apneg, 1, 2, 0.0, 0., &swapp, &swapn);
    cpl_test_error(CPL_ERROR_UNSPECIFIED);

    /* Verify output of correct call - with zero eccentricity */
    ecc = visir_img_check_box(appos, 1, 2, apneg, 1, 2, BOX_SIZE, 0.,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_abs(ecc, 0.0, FLT_EPSILON);
    cpl_test(swapp);
    cpl_test_zero(swapn);

    /* - and points are swapped when needed */
    ecc = visir_img_check_box(appos, 2, 1, apneg, 2, 1, BOX_SIZE, 0.,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_abs(ecc, 0.0, FLT_EPSILON);
    cpl_test_zero(swapp);
    cpl_test(swapn);

    /* Verify output of correct call - with maximum (?) eccentricity */
    ecc = visir_img_check_box(apneg, 1, 2, appos, 1, 2, BOX_SIZE, 0.,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_abs(ecc, 2.0 * CPL_MATH_SQRT2, FLT_EPSILON);
    cpl_test_zero(swapp);
    cpl_test(swapn);

    /* - and points are swapped when needed */
    ecc = visir_img_check_box(apneg, 2, 1, appos, 2, 1, BOX_SIZE, 0.,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_abs(ecc, 2.0 * CPL_MATH_SQRT2, FLT_EPSILON);
    cpl_test(swapp);
    cpl_test_zero(swapn);

    cpl_image_delete(image);
    cpl_apertures_delete(appos);
    cpl_apertures_delete(apneg);

    /* verify with angle 45° */
    image = cpl_image_new(600, 600, CPL_TYPE_INT);
    double throw = 220;

    /* Create four 3x3-pixel objects */
    for (j = -1; j <= 1; j++) {
      for (i = -1; i <= 1; i++) {
          cpl_image_set(image, 350 + i,  80 + j,  1.0);
          cpl_image_set(image, 350 + i, 400 + j,  1.0);
          cpl_image_set(image, 190 + i, 240 + j, -1.0);
          cpl_image_set(image, 510 + i, 240 + j, -1.0);
      }
    }

    appos = cpl_apertures_extract_sigma(image, sigma);
    cpl_image_multiply_scalar(image, -1.0);
    apneg = cpl_apertures_extract_sigma(image, sigma);

    ecc = visir_img_check_box(appos, 1, 2, apneg, 1, 2, throw,
                              45. * CPL_MATH_RAD_DEG,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_rel(ecc, 0.057, 0.1);
    cpl_test(swapp);
    cpl_test_zero(swapn);

    cpl_image_delete(image);
    cpl_apertures_delete(appos);
    cpl_apertures_delete(apneg);

    /* 30° */
    image = cpl_image_new(600, 600, CPL_TYPE_INT);

    for (j = -1; j <= 1; j++) {
      for (i = -1; i <= 1; i++) {
          cpl_image_set(image, 453 + i,  172 + j,  1.0);
          cpl_image_set(image, 373 + i, 470 + j,  1.0);
          cpl_image_set(image, 260 + i, 280 + j, -1.0);
          cpl_image_set(image, 570 + i, 360 + j, -1.0);
      }
    }

    appos = cpl_apertures_extract_sigma(image, sigma);
    cpl_image_multiply_scalar(image, -1.0);
    apneg = cpl_apertures_extract_sigma(image, sigma);

    ecc = visir_img_check_box(appos, 1, 2, apneg, 1, 2, throw,
                              30. * CPL_MATH_RAD_DEG,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_rel(ecc, 0.049, 0.1);
    cpl_test(swapp);
    cpl_test_zero(swapn);

    cpl_image_delete(image);
    cpl_apertures_delete(appos);
    cpl_apertures_delete(apneg);

    /* 85° */
    image = cpl_image_new(600, 600, CPL_TYPE_INT);

    for (j = -1; j <= 1; j++) {
      for (i = -1; i <= 1; i++) {
          cpl_image_set(image, 363 + i,  396 + j,  1.0);
          cpl_image_set(image, 156 + i, 159 + j,  1.0);
          cpl_image_set(image, 138 + i, 382 + j, -1.0);
          cpl_image_set(image, 381 + i, 175 + j, -1.0);
      }
    }

    appos = cpl_apertures_extract_sigma(image, sigma);
    cpl_image_multiply_scalar(image, -1.0);
    apneg = cpl_apertures_extract_sigma(image, sigma);

    ecc = visir_img_check_box(appos, 1, 2, apneg, 1, 2, throw,
                              85. * CPL_MATH_RAD_DEG,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_rel(ecc, 0.049, 0.1);
    cpl_test(swapp);
    /* fails, not required to be correct for aqu pipeline */
    //cpl_test_zero(swapn);

    cpl_image_delete(image);
    cpl_apertures_delete(appos);
    cpl_apertures_delete(apneg);

    if (stream != stdout) cpl_test_zero( fclose(stream) );

}

static void visir_img_check_align_test(void)
{

    FILE          * stream;
    cpl_error_code  error = CPL_ERROR_NONE;
    int             idir;
    cpl_boolean     is_hor = CPL_FALSE;

    stream = cpl_msg_get_level() > CPL_MSG_INFO
        ? fopen("/dev/null", "a") : stdout;

    cpl_test_nonnull( stream );

    for (idir = 0; idir < 2; idir++, is_hor = CPL_TRUE) {
        cpl_image     * image = cpl_image_new(4 * LINE_SIZE, 4 * LINE_SIZE,
                                              CPL_TYPE_INT);
        const double    sigma = 1.0;
        cpl_apertures * appos;
        cpl_apertures * apneg;
        double          ecc;
        cpl_boolean     swapn, swapn2;
        int i, j;
        double dhor = 90 * CPL_MATH_RAD_DEG;


        /* Create three 3x3-pixel objects */
        for (j = -1; j <= 1; j++) {
            for (i = -1; i <= 1; i++) {
                error |= cpl_image_set(image, 2*LINE_SIZE + i,
                                       2*LINE_SIZE + j,  1.0);

                if (is_hor) {
                    error |= cpl_image_set(image,   LINE_SIZE + i,
                                           2*LINE_SIZE + j, -1.0);
                    error |= cpl_image_set(image, 3*LINE_SIZE + i,
                                           2*LINE_SIZE + j, -1.0);
                } else {
                    error |= cpl_image_set(image, 2*LINE_SIZE + i,
                                           LINE_SIZE + j, -1.0);
                    error |= cpl_image_set(image, 2*LINE_SIZE + i,
                                           3*LINE_SIZE + j, -1.0);
                }
                cpl_test_eq_error(error, CPL_ERROR_NONE);
            }
        }

        appos = cpl_apertures_extract_sigma(image, sigma);
        cpl_test_error(CPL_ERROR_NONE);
        cpl_test_nonnull(appos);
        cpl_test_eq(cpl_apertures_get_size(appos), 1);

        cpl_apertures_dump(appos, stream);

        error = cpl_image_multiply_scalar(image, -1.0);
        cpl_test_eq_error(error, CPL_ERROR_NONE);

        apneg = cpl_apertures_extract_sigma(image, sigma);
        cpl_test_error(CPL_ERROR_NONE);
        cpl_test_nonnull(apneg);
        cpl_test_eq(cpl_apertures_get_size(apneg), 2);

        cpl_apertures_dump(apneg, stream);

        /* Various error checks */
        ecc = visir_img_check_align(NULL, 1, apneg, 1, 2, LINE_SIZE, 0.,
                                    &swapn);
        cpl_test_error(CPL_ERROR_NULL_INPUT);

        ecc = visir_img_check_align(appos, 1, NULL, 1, 2, LINE_SIZE, 0.,
                                    &swapn);
        cpl_test_error(CPL_ERROR_NULL_INPUT);

        ecc = visir_img_check_align(appos, 1, apneg, 1, 2, LINE_SIZE, 0.,
                                    NULL);
        cpl_test_error(CPL_ERROR_UNSPECIFIED);

        ecc = visir_img_check_align(appos, 0, apneg, 1, 2, LINE_SIZE, 0.,
                                    &swapn);
        cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

        ecc = visir_img_check_align(appos, 1, apneg, 1, 0, LINE_SIZE, 0.,
                                    &swapn);
        cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

        ecc = visir_img_check_align(appos, 1, apneg, 0, 1, LINE_SIZE, 0.,
                                    &swapn);
        cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

        ecc = visir_img_check_align(appos, 1, apneg, 1, 3, LINE_SIZE, 0.,
                                    &swapn);
        cpl_test_error(CPL_ERROR_ACCESS_OUT_OF_RANGE);

        ecc = visir_img_check_align(appos, 3, apneg, 1, 2, LINE_SIZE, 0.,
                                    &swapn);
        cpl_test_error(CPL_ERROR_ACCESS_OUT_OF_RANGE);

        ecc = visir_img_check_align(appos, 1, apneg, 1, 2, 0.0, 0., &swapn);
        cpl_test_error(CPL_ERROR_UNSPECIFIED);

        /* Verify output of correct call - with zero eccentricity */
        ecc = visir_img_check_align(appos, 1, apneg, 1, 2, LINE_SIZE,
                                    is_hor ? dhor : 0., &swapn);
        cpl_test_error(CPL_ERROR_NONE);

        cpl_test_abs(ecc, 0.0, FLT_EPSILON);
        cpl_test_zero(swapn);

        /* - and points are swapped when needed */
        ecc = visir_img_check_align(appos, 1, apneg, 2, 1, LINE_SIZE,
                                    is_hor ? dhor : 0., &swapn);
        cpl_test_error(CPL_ERROR_NONE);

        cpl_test_abs(ecc, 0.0, FLT_EPSILON);
        cpl_test(swapn);

        /* Verify output of correct call - with maximum (?) eccentricity */
        ecc = visir_img_check_align(appos, 1, apneg, 1, 2, LINE_SIZE,
                                     !is_hor ? dhor : 0., &swapn);
        cpl_test_error(CPL_ERROR_NONE);

        cpl_test_abs(ecc, 2.0, FLT_EPSILON);

        /* - also with points swapped */
        ecc = visir_img_check_align(appos, 1, apneg, 2, 1, LINE_SIZE,
                                     !is_hor ? dhor : 0. ,&swapn2);
        cpl_test_error(CPL_ERROR_NONE);

        cpl_test_abs(ecc, 2.0, FLT_EPSILON);

        /* FIXME: When to exactly swap here is not well-defined. */

        cpl_image_delete(image);
        cpl_apertures_delete(appos);
        cpl_apertures_delete(apneg);
    }

    if (stream != stdout) cpl_test_zero( fclose(stream) );

}

static void visir_img_check_line_test(void)
{

    FILE          * stream;
    cpl_error_code  error = CPL_ERROR_NONE;
    int             idir;
    cpl_boolean     is_hor = CPL_FALSE;

    stream = cpl_msg_get_level() > CPL_MSG_INFO
        ? fopen("/dev/null", "a") : stdout;

    cpl_test_nonnull( stream );

    for (idir = 0; idir < 2; idir++, is_hor = CPL_TRUE) {
        cpl_image     * image = cpl_image_new(4 * LINE_SIZE, 4 * LINE_SIZE,
                                              CPL_TYPE_INT);
        const double    sigma = 1.0;
        cpl_apertures * appos;
        cpl_apertures * apneg;
        double          ecc;
        int i, j;
        double dhor = 90 * CPL_MATH_RAD_DEG;


        /* Create three 3x3-pixel objects */
        for (j = -1; j <= 1; j++) {
            for (i = -1; i <= 1; i++) {
                error |= cpl_image_set(image, 2*LINE_SIZE + i,
                                       2*LINE_SIZE + j,  1.0);

                if (is_hor) {
                    error |= cpl_image_set(image,   LINE_SIZE + i,
                                           2*LINE_SIZE + j, -1.0);
                    error |= cpl_image_set(image, 3*LINE_SIZE + i,
                                           2*LINE_SIZE + j, -1.0);
                } else {
                    error |= cpl_image_set(image, 2*LINE_SIZE + i,
                                           LINE_SIZE + j, -1.0);
                    error |= cpl_image_set(image, 2*LINE_SIZE + i,
                                           3*LINE_SIZE + j, -1.0);
                }
                cpl_test_eq_error(error, CPL_ERROR_NONE);
            }
        }

        appos = cpl_apertures_extract_sigma(image, sigma);
        cpl_test_error(CPL_ERROR_NONE);
        cpl_test_nonnull(appos);
        cpl_test_eq(cpl_apertures_get_size(appos), 1);

        cpl_apertures_dump(appos, stream);

        error = cpl_image_multiply_scalar(image, -1.0);
        cpl_test_eq_error(error, CPL_ERROR_NONE);

        apneg = cpl_apertures_extract_sigma(image, sigma);
        cpl_test_error(CPL_ERROR_NONE);
        cpl_test_nonnull(apneg);
        cpl_test_eq(cpl_apertures_get_size(apneg), 2);

        cpl_apertures_dump(apneg, stream);

        /* Various error checks */
        ecc = visir_img_check_line(NULL, 1, apneg, 1, LINE_SIZE, 0.);
        cpl_test_error(CPL_ERROR_NULL_INPUT);

        ecc = visir_img_check_line(appos, 1, NULL, 1, LINE_SIZE, 0.);
        cpl_test_error(CPL_ERROR_NULL_INPUT);

        ecc = visir_img_check_line(appos, 0, apneg, 1, LINE_SIZE, 0.);
        cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

        ecc = visir_img_check_line(appos, 1, apneg, 0, LINE_SIZE, 0.);
        cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

        ecc = visir_img_check_line(appos, 1, apneg, 0, LINE_SIZE, 0.);
        cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

        ecc = visir_img_check_line(appos, 1, apneg, 3, LINE_SIZE, 0.);
        cpl_test_error(CPL_ERROR_ACCESS_OUT_OF_RANGE);

        ecc = visir_img_check_line(appos, 3, apneg, 1, LINE_SIZE, 0.);
        cpl_test_error(CPL_ERROR_ACCESS_OUT_OF_RANGE);

        ecc = visir_img_check_line(appos, 1, apneg, 1, 0.0, 0.);
        cpl_test_error(CPL_ERROR_UNSPECIFIED);

        /* Verify output of correct call - with zero eccentricity */
        ecc = visir_img_check_line(apneg, 1, appos, 1, LINE_SIZE,
                                   is_hor ? dhor : 0.);
        cpl_test_error(CPL_ERROR_NONE);

        cpl_test_abs(ecc, 0.0, FLT_EPSILON);

        /* Verify output of correct call - with maximum (?) eccentricity */
        ecc = visir_img_check_line(appos, 1, apneg, 1, LINE_SIZE,
                                   is_hor ? dhor : 0.);
        cpl_test_error(CPL_ERROR_NONE);

        cpl_test_abs(ecc, 2.0, FLT_EPSILON);

        /* Verify output of correct call - with maximum (?) eccentricity */
        ecc = visir_img_check_line(appos, 1, apneg, 1, LINE_SIZE,
                                   !is_hor ? dhor : 0.);
        cpl_test_error(CPL_ERROR_NONE);

        cpl_test_abs(ecc, CPL_MATH_SQRT2, FLT_EPSILON);

        /* - also with points swapped */
        ecc = visir_img_check_line(apneg, 1, appos, 1, LINE_SIZE,
                                   !is_hor ? dhor : 0.);
        cpl_test_error(CPL_ERROR_NONE);

        cpl_test_abs(ecc, CPL_MATH_SQRT2, FLT_EPSILON);

        /* FIXME: When to exactly swap here is not well-defined. */

        cpl_image_delete(image);
        cpl_apertures_delete(appos);
        cpl_apertures_delete(apneg);
    }

    if (stream != stdout) cpl_test_zero( fclose(stream) );

}

static void load_frame(const char * fn, cpl_frame ** frm,
                       cpl_propertylist ** plist, const int iext)
{
    *frm = cpl_frame_new();
    cpl_frame_set_filename(*frm, fn);
    *plist = cpl_propertylist_load(fn, iext);
}


static void visir_check_get_type(void)
{

    FILE          * stream;
    const char * fn = "get_type_check.fits";

    stream = cpl_msg_get_level() > CPL_MSG_INFO
        ? fopen("/dev/null", "a") : stdout;

    cpl_propertylist * plist;
    cpl_imagelist * l;
    cpl_frame * frm;
    cpl_propertylist * lplist;
    cpl_size next;
    visir_data_type type;

    /* CUBE1 */
    {
        l = cpl_imagelist_new();
        plist = cpl_propertylist_new();
        cpl_propertylist_append_string(plist, VISIR_PFITS_STRING_FRAME_TYPE,
                                       "CUBE1");
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_CHOP_NCYCLES, 2);
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_NDIT, 10);
        for (int i = 0; i < 4; i++)
            cpl_imagelist_set(l, cpl_image_new(4, 4, CPL_TYPE_INT), i);
        cpl_imagelist_save(l, fn, CPL_TYPE_INT, plist, CPL_IO_CREATE);
        load_frame(fn, &frm, &lplist, 0);

        visir_get_data_type(frm, lplist, &type, &next);
        cpl_test_error(CPL_ERROR_NONE);
        cpl_test_eq(VISIR_DATA_CUBE1, type);
        cpl_test_eq(0, next);

        cpl_frame_delete(frm);
        cpl_propertylist_delete(lplist);
        cpl_imagelist_delete(l);
        cpl_propertylist_delete(plist);
    }

    /* CUBE2 */
    {
        l = cpl_imagelist_new();
        plist = cpl_propertylist_new();
        cpl_propertylist_append_string(plist, VISIR_PFITS_STRING_FRAME_TYPE,
                                       "CUBE2");
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_CHOP_NCYCLES, 5);
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_NDIT, 10);
        for (int i = 0; i < 5 * 2 + 1; i++)
            cpl_imagelist_set(l, cpl_image_new(4, 4, CPL_TYPE_INT), i);
        cpl_imagelist_save(l, fn, CPL_TYPE_INT, plist, CPL_IO_CREATE);
        load_frame(fn, &frm, &lplist, 0);

        visir_get_data_type(frm, lplist, &type, &next);
        cpl_test_error(CPL_ERROR_NONE);
        cpl_test_eq(VISIR_DATA_CUBE2, type);
        cpl_test_eq(0, next);

        cpl_frame_delete(frm);
        cpl_propertylist_delete(lplist);
        cpl_imagelist_delete(l);
        cpl_propertylist_delete(plist);
    }

    /* BURST */
    {
        l = cpl_imagelist_new();
        plist = cpl_propertylist_new();
        cpl_propertylist_append_string(plist, VISIR_PFITS_STRING_FRAME_TYPE,
                                       "UNDEFINED");
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_CHOP_NCYCLES, 5);
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_NDIT, 10);
        for (int i = 0; i < 5 * 2 * 10; i++)
            cpl_imagelist_set(l, cpl_image_new(4, 4, CPL_TYPE_INT), i);
        cpl_imagelist_save(l, fn, CPL_TYPE_INT, plist, CPL_IO_CREATE);
        load_frame(fn, &frm, &lplist, 0);

        visir_get_data_type(frm, lplist, &type, &next);
        cpl_test_error(CPL_ERROR_NONE);
        cpl_test_eq(VISIR_DATA_BURST, type);
        cpl_test_eq(0, next);

        cpl_frame_delete(frm);
        cpl_propertylist_delete(lplist);
        cpl_imagelist_delete(l);
        cpl_propertylist_delete(plist);
    }

    /* BURST incomplete*/
    {
        l = cpl_imagelist_new();
        plist = cpl_propertylist_new();
        cpl_propertylist_append_string(plist, VISIR_PFITS_STRING_FRAME_TYPE,
                                       "UNDEFINED");
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_CHOP_NCYCLES, 5);
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_NDIT, 10);
        for (int i = 0; i < 5 * 2 * 10 - 10; i++)
            cpl_imagelist_set(l, cpl_image_new(4, 4, CPL_TYPE_INT), i);
        cpl_imagelist_save(l, fn, CPL_TYPE_INT, plist, CPL_IO_CREATE);
        load_frame(fn, &frm, &lplist, 0);

        visir_get_data_type(frm, lplist, &type, &next);
        cpl_test_error(CPL_ERROR_NONE);
        cpl_test_eq(VISIR_DATA_BURST, type);
        cpl_test_eq(0, next);

        cpl_frame_delete(frm);
        cpl_propertylist_delete(lplist);
        cpl_imagelist_delete(l);
        cpl_propertylist_delete(plist);
    }

    /* AQU HCYCLE */
    {
        cpl_image * img = cpl_image_new(4, 4, CPL_TYPE_INT);
        plist = cpl_propertylist_new();
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_NAVRG, 1);
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_CHOP_NCYCLES, 5);
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_NDIT, 10);
        cpl_propertylist_save(plist, fn, CPL_IO_CREATE);
        for (int i = 0; i < 5 * 2 + 1; i++)
            cpl_image_save(img, fn, CPL_TYPE_INT, NULL, CPL_IO_EXTEND);
        load_frame(fn, &frm, &lplist, 0);

        visir_get_data_type(frm, lplist, &type, &next);
        cpl_test_error(CPL_ERROR_NONE);
        cpl_test_eq(VISIR_DATA_AQU_HCYCLE, type);
        cpl_test_eq(11, next);

        cpl_frame_delete(frm);
        cpl_propertylist_delete(lplist);
        cpl_image_delete(img);
        cpl_propertylist_delete(plist);
    }

    /* AQU BURST */
    {
        plist = cpl_propertylist_new();
        l = cpl_imagelist_new();
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_NAVRG, 1);
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_CHOP_NCYCLES, 5);
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_NDIT, 10);
        for (int i = 0; i < 5 * 2 * 10; i++)
            cpl_imagelist_set(l, cpl_image_new(4, 4, CPL_TYPE_INT), i);
        cpl_imagelist_save(l, fn, CPL_TYPE_INT, plist, CPL_IO_CREATE);
        load_frame(fn, &frm, &lplist, 0);

        visir_get_data_type(frm, lplist, &type, &next);
        cpl_test_error(CPL_ERROR_NONE);
        cpl_test_eq(VISIR_DATA_AQU_BURST, type);
        cpl_test_eq(0, next);

        cpl_frame_delete(frm);
        cpl_propertylist_delete(lplist);
        cpl_imagelist_delete(l);
        cpl_propertylist_delete(plist);
    }
    
    /* AQU BURST EXT */
    {
        plist = cpl_propertylist_new();
        l = cpl_imagelist_new();
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_NAVRG, 1);
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_CHOP_NCYCLES, 5);
        cpl_propertylist_append_int(plist, VISIR_PFITS_INT_NDIT, 10);
        cpl_propertylist_save(plist, fn, CPL_IO_CREATE);
        for (int i = 0; i < 5 * 2 * 10; i++)
            cpl_imagelist_set(l, cpl_image_new(4, 4, CPL_TYPE_INT), i);
        cpl_imagelist_save(l, fn, CPL_TYPE_INT, NULL, CPL_IO_EXTEND);
        load_frame(fn, &frm, &lplist, 0);

        visir_get_data_type(frm, lplist, &type, &next);
        cpl_test_error(CPL_ERROR_NONE);
        cpl_test_eq(VISIR_DATA_AQU_BURST_EXT, type);
        cpl_test_eq(1, next);

        cpl_frame_delete(frm);
        cpl_propertylist_delete(lplist);
        cpl_imagelist_delete(l);
        cpl_propertylist_delete(plist);
    }

    unlink(fn);
    if (stream != stdout) cpl_test_zero( fclose(stream) );
}

static cpl_propertylist * create_property_list(const char * obs_start,
                                               const char * chop_start,
                                               const double chop_freq,
                                               const double dit,
                                               const double nditskip)
{
    cpl_propertylist * prop = cpl_propertylist_new();
    cpl_propertylist_append_string(prop, VISIR_PFITS_STRING_OBS_START,
            obs_start);
    cpl_propertylist_append_string(prop, VISIR_PFITS_STRING_CHOP_START,
            chop_start);
    cpl_propertylist_append_double(prop, VISIR_PFITS_DOUBLE_CHOP_FREQ,
            chop_freq);
    cpl_propertylist_append_double(prop, VISIR_PFITS_DOUBLE_DIT, dit);
    cpl_propertylist_append_int(prop, VISIR_PFITS_INT_NDITSKIP, nditskip);
    return prop;
}

static void visir_img_check_burst_find_delta_chop(void)
{

    FILE          * stream;

    stream = cpl_msg_get_level() > CPL_MSG_INFO
        ? fopen("/dev/null", "a") : stdout;

    cpl_test_nonnull( stream );

    {
        int ifirst = 0, ihalfcycle = 0;
        cpl_propertylist * prop =
            create_property_list("2011-08-13T23:13:38.0612",
                                 "2011-08-13T23:10:16",
                                 0.25, 0.02, 2);
        visir_img_burst_find_delta_chop(prop, &ifirst, &ihalfcycle);
        cpl_test_eq(94, ifirst);
        cpl_test_eq(100, ihalfcycle);
        cpl_propertylist_delete(prop);
    }

    {
        int ifirst = 0, ihalfcycle = 0;
        cpl_propertylist * prop =
            create_property_list("2011-08-13T23:10:16.0612",
                                 "2011-08-13T23:13:38",
                                 0.25, 0.02, 2);
        visir_img_burst_find_delta_chop(prop, &ifirst, &ihalfcycle);
        cpl_test_eq(94, ifirst);
        cpl_test_eq(100, ihalfcycle);
        cpl_propertylist_delete(prop);
    }

    {
        int ifirst = 0, ihalfcycle = 0;
        cpl_propertylist * prop =
            create_property_list("2011-08-13T23:13:35.9999",
                                 "2011-08-13T23:10:16",
                                 0.25, 0.02, 0);
        visir_img_burst_find_delta_chop(prop, &ifirst, &ihalfcycle);
        cpl_test_eq(0, ifirst);
        cpl_test_eq(100, ihalfcycle);
        cpl_propertylist_delete(prop);
    }
    /* ichopchange > ihalfcycle testcase in visir_img_check_load_burst */

    if (stream != stdout) cpl_test_zero( fclose(stream) );

}

static cpl_imagelist * create_input_imagelist(const int * values, int naxis3)
{
    cpl_imagelist * list = cpl_imagelist_new();
    for (int i = 0; i < naxis3; i++) {
        cpl_image * image = cpl_image_new(3 * BOX_SIZE, 3 * BOX_SIZE,
                                          CPL_TYPE_INT);
        cpl_image_set(image, 1, 1, values[i]);
        cpl_imagelist_set(list, image, cpl_imagelist_get_size(list));
    }
    return list;
}

static void visir_img_check_load_burst(void)
{
    FILE          * stream;

    stream = cpl_msg_get_level() > CPL_MSG_INFO
        ? fopen("/dev/null", "a") : stdout;

    cpl_test_nonnull( stream );

    /* large data test */
    {
        cpl_imagelist * list = cpl_imagelist_new();
        cpl_imagelist * blist = cpl_imagelist_new();
        cpl_imagelist * alist = cpl_imagelist_new();
        cpl_propertylist * prop;
        int naxis3 = 100;
        int ichopchange = 0, ihalfcycle = 0;

        prop = create_property_list("2011-08-13T23:11:04.0000",
                                    "2011-08-13T23:10:00", 0.1, 1, 0);
        // chopstart 6
        visir_img_burst_find_delta_chop(prop, &ichopchange, &ihalfcycle);
        cpl_test_eq(6, ichopchange);
        cpl_test_eq(5, ihalfcycle);

        for (int i = 0; i < naxis3; i++) {
            cpl_image * image = cpl_image_new(3 * BOX_SIZE, 3 * BOX_SIZE,
                                              CPL_TYPE_INT);
            cpl_image_set(image, 1, 1, 0xA);

            cpl_imagelist_set(list, image, cpl_imagelist_get_size(list));
        }
        /* mark images to skip bad (1, 6, 11, 16, ...) */
        for (int i = 0; i< 20; i++) {
            cpl_image * img = 
                cpl_imagelist_get(list,
                                  i * ihalfcycle + (ichopchange % ihalfcycle));
            cpl_image_set(img, 1, 1, 0xBADBEEF);
        }

        visir_load_burst_(alist, blist, list, ichopchange, ihalfcycle, 0, 0);
        cpl_test_eq(40, cpl_imagelist_get_size(alist));
        cpl_test_eq(40, cpl_imagelist_get_size(blist));

        TEST_LIST(alist, 0xA);
        TEST_LIST(blist, 0xA);

        cpl_imagelist_delete(alist);
        cpl_imagelist_delete(blist);
        cpl_imagelist_delete(list);
        cpl_propertylist_delete(prop);
    }


    /* detailed test small data */
    {
        cpl_imagelist * alist = cpl_imagelist_new();
        cpl_imagelist * blist = cpl_imagelist_new();
        cpl_propertylist * prop;
        const int values[] = {0xB, 0xBADBEEF, 0xA, 0xA, 0xA, 0xA, 0xBADBEEF,
                              0xB, 0xB, 0xB, 0xB, 0xBADBEEF};
        int naxis3 =sizeof(values)/sizeof(values[0]);
        int ichopchange = 0, ihalfcycle = 0;
        cpl_imagelist * list = create_input_imagelist(values, naxis3);

        // halfcycle 5, chopstart 6
        prop = create_property_list("2011-08-13T23:11:04.0000",
                                    "2011-08-13T23:10:00", 0.1, 1, 0);
        visir_img_burst_find_delta_chop(prop, &ichopchange, &ihalfcycle);
        cpl_test_eq(6, ichopchange);
        cpl_test_eq(5, ihalfcycle);

        visir_load_burst_(alist, blist, list, ichopchange, ihalfcycle, 0, 0);
        cpl_test_eq(4, cpl_imagelist_get_size(alist));
        cpl_test_eq(5, cpl_imagelist_get_size(blist));

        TEST_LIST(alist, 0xA);
        TEST_LIST(blist, 0xB);

        cpl_imagelist_delete(list);

        /* test trimming */

        list = create_input_imagelist(values, naxis3);
        cpl_imagelist_empty(alist);
        cpl_imagelist_empty(blist);

        visir_load_burst_(alist, blist, list, ichopchange, ihalfcycle, 1, 1);
        cpl_test_eq(2, cpl_imagelist_get_size(alist));
        cpl_test_eq(2, cpl_imagelist_get_size(blist));

        TEST_LIST(alist, 0xA);
        TEST_LIST(blist, 0xB);

        cpl_imagelist_delete(list);

        /* test trimming ichopchange % ihalfcycle - trim < 0*/

        list = create_input_imagelist(values, naxis3);
        cpl_imagelist_empty(alist);
        cpl_imagelist_empty(blist);

        visir_load_burst_(alist, blist, list, ichopchange, ihalfcycle, 2, 1);
        cpl_test_eq(1, cpl_imagelist_get_size(alist));
        cpl_test_eq(1, cpl_imagelist_get_size(blist));

        TEST_LIST(alist, 0xA);
        TEST_LIST(blist, 0xB);

        cpl_imagelist_delete(list);

        /* test full chop/trim range*/

        for (int i = 0; i < ihalfcycle * 2; i++) {
            for (int h = 0; h < ihalfcycle / 2; h++) {
                for (int l = 0; l < ihalfcycle / 2; l++) {
                    list = create_input_imagelist(values, naxis3);
                    cpl_imagelist_empty(alist);
                    cpl_imagelist_empty(blist);

                    visir_load_burst_(alist, blist, list, i, ihalfcycle, l, h);
                    // FIXME: test non trim case too
                    while (cpl_imagelist_get_size(alist) < cpl_imagelist_get_size(blist))
                        cpl_image_delete(cpl_imagelist_unset(blist, cpl_imagelist_get_size(blist) - 1));
                    while (cpl_imagelist_get_size(alist) > cpl_imagelist_get_size(blist))
                        cpl_image_delete(cpl_imagelist_unset(alist, cpl_imagelist_get_size(alist) - 1));
                    cpl_test_eq(4 - (h + l), cpl_imagelist_get_size(alist));
                    cpl_test_eq(4 - (h + l), cpl_imagelist_get_size(blist));

                    cpl_imagelist_delete(list);
                }
            }
        }

        cpl_imagelist_delete(alist);
        cpl_imagelist_delete(blist);
        cpl_propertylist_delete(prop);
    }

    /* test assymmetric rejects */
    {
        cpl_imagelist * blist = cpl_imagelist_new();
        cpl_imagelist * alist = cpl_imagelist_new();
        const int values[] = {0, 1, 1, 0, 0, 0xBAD, 0, 1, 1, 0, 0, 0xBAD, 0, 1};
        int naxis3 = sizeof(values)/sizeof(values[0]);
        int ichopchange = 5, ihalfcycle = 6;
        cpl_imagelist * list = create_input_imagelist(values, naxis3);

        visir_load_burst_(alist, blist, list, ichopchange, ihalfcycle, 2, 1);
        cpl_test_eq(3, cpl_imagelist_get_size(alist));
        cpl_test_eq(2, cpl_imagelist_get_size(blist));

        TEST_LIST(alist, 1);
        TEST_LIST(blist, 1);

        cpl_imagelist_delete(list);
        cpl_imagelist_delete(alist);
        cpl_imagelist_delete(blist);
    }

    /* sliced with chopchange in first half cycle */
    {
        cpl_imagelist * blist = cpl_imagelist_new();
        cpl_imagelist * alist = cpl_imagelist_new();
        cpl_propertylist * prop;
        const int values[] = {0xA, 0xBADBEEF, 0xB, 0xB, 0xB, 0xB, 0xBADBEEF,
                              0xA, 0xA, 0xA, 0xA, 0xBADBEEF};
        int naxis3 = sizeof(values)/sizeof(values[0]);
        int ichopchange = 0, ihalfcycle = 0;
        cpl_imagelist * list = create_input_imagelist(values, naxis3);

        // halfcycle 5, chopstart 1
        prop = create_property_list("2011-08-13T23:11:09.0000",
                                    "2011-08-13T23:10:00", 0.1, 1, 0);
        visir_img_burst_find_delta_chop(prop, &ichopchange, &ihalfcycle);
        cpl_test_eq(1, ichopchange);
        cpl_test_eq(5, ihalfcycle);

        visir_load_burst_(alist, blist, list, ichopchange, ihalfcycle, 0, 0);
        cpl_test_eq(5, cpl_imagelist_get_size(alist));
        cpl_test_eq(4, cpl_imagelist_get_size(blist));

        TEST_LIST(alist, 0xA);
        TEST_LIST(blist, 0xB);

        cpl_imagelist_delete(list);
        cpl_imagelist_delete(alist);
        cpl_imagelist_delete(blist);
        cpl_propertylist_delete(prop);
    }

    {
        cpl_imagelist * blist = cpl_imagelist_new();
        cpl_imagelist * alist = cpl_imagelist_new();
        cpl_propertylist * prop;
        const int values[] = {0xBADBEEF, 0xB, 0xB, 0xB, 0xB, 0xBADBEEF,
                              0xA, 0xA, 0xA, 0xA, 0xBADBEEF, 0xB};
        int naxis3 = sizeof(values)/sizeof(values[0]);
        int ichopchange = 0, ihalfcycle = 0;
        cpl_imagelist * list = create_input_imagelist(values, naxis3);

        // halfcycle 5, chopstart 0
        prop = create_property_list("2011-08-13T23:10:00.0000",
                                    "2011-08-13T23:10:00", 0.1, 1, 0);
        visir_img_burst_find_delta_chop(prop, &ichopchange, &ihalfcycle);
        cpl_test_eq(0, ichopchange);
        cpl_test_eq(5, ihalfcycle);

        visir_load_burst_(alist, blist, list, ichopchange, ihalfcycle, 0, 0);
        cpl_test_eq(4, cpl_imagelist_get_size(alist));
        cpl_test_eq(5, cpl_imagelist_get_size(blist));

        TEST_LIST(alist, 0xA);
        TEST_LIST(blist, 0xB);

        cpl_imagelist_delete(list);
        cpl_imagelist_delete(alist);
        cpl_imagelist_delete(blist);
        cpl_propertylist_delete(prop);
    }

    {
        const char * fn = "load_burst.fits";
        cpl_imagelist * blist = cpl_imagelist_new();
        cpl_imagelist * alist = cpl_imagelist_new();
        cpl_propertylist * prop = cpl_propertylist_new();
        cpl_frame * frame = cpl_frame_new();
        const int values[] = {0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA};
        int naxis3 = sizeof(values)/sizeof(values[0]);
        cpl_imagelist * list = create_input_imagelist(values, naxis3);

        cpl_propertylist_append_bool(prop, VISIR_PFITS_BOOL_CHOP_STATUS, CPL_FALSE);
        cpl_imagelist_save(list, fn, CPL_TYPE_UNSPECIFIED,
                           prop, CPL_IO_CREATE);
        cpl_propertylist_delete(prop);
        prop = cpl_propertylist_load(fn, 0);
        cpl_frame_set_filename(frame, fn);

        // TODO reenable when chop st is fixed
        //visir_load_burst(alist, blist, frame, prop, 0, naxis3, 0, naxis3, 0, 0);
        //cpl_test_eq(naxis3, cpl_imagelist_get_size(alist));
        //cpl_test_eq(0, cpl_imagelist_get_size(blist));

        TEST_LIST(alist, 0xA);

        cpl_imagelist_delete(list);
        cpl_imagelist_delete(alist);
        cpl_imagelist_delete(blist);
        cpl_propertylist_delete(prop);
        cpl_frame_delete(frame);
        unlink(fn);
    }

    if (stream != stdout) cpl_test_zero( fclose(stream) );

}


static void visir_img_check_get_to_off_plane(void)
{

    FILE          * stream;

    stream = cpl_msg_get_level() > CPL_MSG_INFO
        ? fopen("/dev/null", "a") : stdout;

    cpl_test_nonnull( stream );

    {
        /* cc < hc tests */
        int icc = 27;
        int istart = 0;
        int ihc = 100;
        cpl_test_eq(27, get_to_off_plane(icc, istart, ihc));

        istart = 10;
        cpl_test_eq(17, get_to_off_plane(icc, istart, ihc));

        istart = icc;
        cpl_test_eq(0, get_to_off_plane(icc, istart, ihc));

        istart = 50;
        cpl_test_eq(177, get_to_off_plane(icc, istart, ihc));

        istart = ihc;
        cpl_test_eq(127, get_to_off_plane(icc, istart, ihc));

        istart = ihc + icc;
        cpl_test_eq(100, get_to_off_plane(icc, istart, ihc));

        istart = 150;
        cpl_test_eq(77, get_to_off_plane(icc, istart, ihc));

        istart = ihc * 2;
        cpl_test_eq(27, get_to_off_plane(icc, istart, ihc));

        istart = ihc * 2 + 10;
        cpl_test_eq(17, get_to_off_plane(icc, istart, ihc));

        istart = ihc * 2 + 50;
        cpl_test_eq(177, get_to_off_plane(icc, istart, ihc));

        istart = 50;
        ihc = 80;
        cpl_test_eq(139, get_to_off_plane(29, istart, ihc));

        /* cc > hc tests */
        icc = 157;
        istart = 240;
        ihc = 80;
        cpl_test_eq(317 - istart, get_to_off_plane(icc, istart, ihc));

        istart = 230;
        cpl_test_eq(317 - istart, get_to_off_plane(icc, istart, ihc));

        istart = 160;
        cpl_test_eq(317 - istart, get_to_off_plane(icc, istart, ihc));

        istart = 150;
        cpl_test_eq(157 - istart, get_to_off_plane(icc, istart, ihc));

        istart = 320;
        cpl_test_eq(477 - istart, get_to_off_plane(icc, istart, ihc));

        istart = 310;
        cpl_test_eq(317 - istart, get_to_off_plane(icc, istart, ihc));

        /* cc == hc tests */
        icc = 80;
        istart = 0;
        ihc = 80;
        cpl_test_eq(80, get_to_off_plane(icc, istart, ihc));

        istart = 80;
        cpl_test_eq(0, get_to_off_plane(icc, istart, ihc));

        istart = 160;
        cpl_test_eq(80, get_to_off_plane(icc, istart, ihc));

        istart = 240;
        cpl_test_eq(0, get_to_off_plane(icc, istart, ihc));

        istart = 30;
        cpl_test_eq(50, get_to_off_plane(icc, istart, ihc));

        istart = 130;
        cpl_test_eq(110, get_to_off_plane(icc, istart, ihc));
    }

    if (stream != stdout) cpl_test_zero( fclose(stream) );
}

/* creates cube2 formated list, length 2*n + 1 */
static cpl_imagelist * create_cube2_imagelist(int ncycles)
{
    cpl_imagelist * list = cpl_imagelist_new();
    cpl_image * image = cpl_image_new(3, 3, CPL_TYPE_FLOAT);
    float prev_val = 0.0;

    for (int i = 0; i < ncycles; i++) {
        const float val = (prev_val * i + A_VAL - B_VAL) / (i + 1);
        cpl_image_set(image, 1, 1, A_VAL - VISIR_HCYCLE_OFFSET);
        cpl_imagelist_set(list, image, cpl_imagelist_get_size(list));
        image = cpl_image_new(3, 3, CPL_TYPE_FLOAT);

        cpl_image_set(image, 1, 1, val);
        cpl_imagelist_set(list, image, cpl_imagelist_get_size(list));
        image = cpl_image_new(3, 3, CPL_TYPE_FLOAT);
        prev_val = val;
    }

    cpl_image_set(image, 1, 1, prev_val);
    cpl_imagelist_set(list, image, cpl_imagelist_get_size(list));
    return list;
}

static void visir_img_check_load_cube2(void)
{

    FILE          * stream;

    stream = cpl_msg_get_level() > CPL_MSG_INFO
        ? fopen("/dev/null", "a") : stdout;

    cpl_test_nonnull( stream );

    {
        const int ncycles = 20;
        cpl_imagelist * list = create_cube2_imagelist(ncycles);
        cpl_imagelist * alist = cpl_imagelist_new();
        cpl_imagelist * blist = cpl_imagelist_new();
        cpl_test_eq(2 * ncycles + 1, cpl_imagelist_get_size(list));

        /* strip the sum */
        cpl_image_delete(cpl_imagelist_unset(list, cpl_imagelist_get_size(list) - 1));

        visir_load_cube2_split_(alist, blist, list, NULL);
        cpl_test_eq(ncycles, cpl_imagelist_get_size(alist));
        cpl_test_eq(ncycles, cpl_imagelist_get_size(blist));
        TEST_LIST(alist, A_VAL);
        TEST_LIST(blist, B_VAL);

        cpl_imagelist_delete(list);
        cpl_imagelist_delete(alist);
        cpl_imagelist_delete(blist);
    }

    /* test chunks */
    {
        const int ncycles = 40;
        cpl_image * prevd;
        cpl_imagelist * list = create_cube2_imagelist(ncycles);
        cpl_imagelist * alist = cpl_imagelist_new();
        cpl_imagelist * blist = cpl_imagelist_new();
        cpl_imagelist * chunk2 = cpl_imagelist_new();

        cpl_test_eq(2 * ncycles + 1, cpl_imagelist_get_size(list));

        /* strip the sum */
        cpl_image_delete(cpl_imagelist_unset(list,
                                             cpl_imagelist_get_size(list) - 1));

        for (int i = ncycles; i > 0; i--) {
            cpl_image * tmp =
                cpl_imagelist_unset(list, cpl_imagelist_get_size(list) - i);
            cpl_imagelist_set(chunk2, tmp, cpl_imagelist_get_size(chunk2));
        }
        prevd =
            cpl_image_duplicate(cpl_imagelist_get(list,
                                                  cpl_imagelist_get_size(list) - 1));

        visir_load_cube2_split_(alist, blist, list, NULL);
        cpl_test_eq(ncycles / 2, cpl_imagelist_get_size(alist));
        cpl_test_eq(ncycles / 2, cpl_imagelist_get_size(blist));
        TEST_LIST(alist, A_VAL);
        TEST_LIST(blist, B_VAL);

        cpl_imagelist_empty(alist);
        cpl_imagelist_empty(blist);

        visir_load_cube2_split_(alist, blist, chunk2, prevd);
        cpl_test_eq(ncycles / 2, cpl_imagelist_get_size(alist));
        cpl_test_eq(ncycles / 2, cpl_imagelist_get_size(blist));
        TEST_LIST(alist, A_VAL);
        TEST_LIST(blist, B_VAL);

        cpl_imagelist_delete(list);
        cpl_imagelist_delete(chunk2);
        cpl_imagelist_delete(alist);
        cpl_imagelist_delete(blist);
        cpl_image_delete(prevd);
    }

    if (stream != stdout) cpl_test_zero( fclose(stream) );
}
