/*                                                                              *
 *   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"

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

/* TEMPORARY SUPPORT OF CPL 5.x */
#if defined CPL_VERSION_CODE && CPL_VERSION_CODE < CPL_VERSION(6, 0, 0)
#define VISIR_ERROR_ACCESS_OUT_OF_RANGE CPL_ERROR_ILLEGAL_INPUT
#else
#define VISIR_ERROR_ACCESS_OUT_OF_RANGE CPL_ERROR_ACCESS_OUT_OF_RANGE
#endif
/* END TEMPORARY SUPPORT OF CPL 5.x */


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


/*----------------------------------------------------------------------------*/
/**
   @brief   Unit tests of inputs module
**/
/*----------------------------------------------------------------------------*/

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_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);

void cpl_imagelist_empty(cpl_imagelist * self);

#ifndef BOX_SIZE
#define BOX_SIZE 11
#endif

#ifndef LINE_SIZE
#define LINE_SIZE BOX_SIZE
#endif

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_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);

}

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,
                              &swapp, &swapn);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

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

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

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

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

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

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

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

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

    ecc = visir_img_check_box(appos, 1, 2, apneg, 1, 2, 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,
                              &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,
                              &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,
                              &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,
                              &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);

    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;


        /* 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, is_hor,
                                    &swapn);
        cpl_test_error(CPL_ERROR_NULL_INPUT);

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

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

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

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

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

        ecc = visir_img_check_align(appos, 1, apneg, 1, 3, LINE_SIZE, is_hor,
                                    &swapn);
        cpl_test_error(VISIR_ERROR_ACCESS_OUT_OF_RANGE);

        ecc = visir_img_check_align(appos, 3, apneg, 1, 2, LINE_SIZE, is_hor,
                                    &swapn);
        cpl_test_error(VISIR_ERROR_ACCESS_OUT_OF_RANGE);

        ecc = visir_img_check_align(appos, 1, apneg, 1, 2, 0.0, is_hor, &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,
                                    &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,
                                    &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,
                                    &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,
                                    &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;


        /* 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, is_hor);
        cpl_test_error(CPL_ERROR_NULL_INPUT);

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

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

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

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

        ecc = visir_img_check_line(appos, 1, apneg, 3, LINE_SIZE, is_hor);
        cpl_test_error(VISIR_ERROR_ACCESS_OUT_OF_RANGE);

        ecc = visir_img_check_line(appos, 3, apneg, 1, LINE_SIZE, is_hor);
        cpl_test_error(VISIR_ERROR_ACCESS_OUT_OF_RANGE);

        ecc = visir_img_check_line(appos, 1, apneg, 1, 0.0, is_hor);
        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);
        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);
        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);
        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);
        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) );

}

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;
    cpl_error_code  error = CPL_ERROR_NONE;

    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) );

}

#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)

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;
    cpl_error_code  error = CPL_ERROR_NONE;

    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();
        cpl_propertylist * prop;
        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);
    }

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

}


static void visir_img_check_get_to_off_plane(void)
{

    FILE          * stream;
    cpl_error_code  error = CPL_ERROR_NONE;

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

    cpl_test_nonnull( stream );

    {
        const 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));
    }

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

#define A_VAL 4.
#define B_VAL 3.

/* creates cube2 formated list, length 2*n + 1 */
cpl_imagelist * create_cube2_imagelist(int ncycles)
{
    cpl_imagelist * list = cpl_imagelist_new();
    float prev_val = 0;
    for (int i = 0; i < ncycles; i++) {
        cpl_image * image = cpl_image_new(3, 3, CPL_TYPE_FLOAT);
        cpl_image_set(image, 1, 1, A_VAL);
        cpl_imagelist_set(list, image, cpl_imagelist_get_size(list));

        image = cpl_image_new(3, 3, CPL_TYPE_FLOAT);
        float val = (prev_val * i + A_VAL - B_VAL) / (i + 1);
        cpl_image_set(image, 1, 1, val);
        cpl_imagelist_set(list, image, cpl_imagelist_get_size(list));
        prev_val = val;
    }

    cpl_image * image = cpl_image_new(3, 3, CPL_TYPE_FLOAT);
    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;
    cpl_error_code  error = CPL_ERROR_NONE;

    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_test_eq(2 * ncycles + 1, cpl_imagelist_get_size(list));
        cpl_imagelist * chunk2 = cpl_imagelist_new();

        /* 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) );
}
