/*
 * This file is part of the KMOS Library
 * Copyright (C) 2007-2008 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 <string.h>

#include "kmclipm_functions.h"
#include "kmclipm_math.h"

#include "kmo_priv_std_star.h"
#include "kmo_cpl_extensions.h"
#include "kmo_priv_functions.h"
#include "kmo_utils.h"
#include "kmo_debug.h"

/**
    @defgroup kmo_priv_std_star_test   kmo_priv_std_star unit tests

    @{
*/

void kmo_test_verbose_off();
void kmo_test_verbose_on();

/**
    @brief   Test for kmo_get_obj_sky_frame_table()
 */
void test_kmo_get_obj_sky_frame_table(void)
{
/*erwtest*/
    kmo_test_verbose_off();
    kmo_test_verbose_on();

    cpl_test_error(CPL_ERROR_NONE);
}

/**
    @brief   Test for kmo_collapse_object_sky_frame_table()
 */
void test_kmo_collapse_object_sky_frame_table(void)
{
/*erwtest*/
    kmo_test_verbose_off();
    kmo_test_verbose_on();

    cpl_test_error(CPL_ERROR_NONE);
}

/**
    @brief   Test for kmo_interpolate_vector_wcs()
 */
void test_kmo_interpolate_vector_wcs(void)
{
    kmo_test_verbose_off();
    // missing inputs
    cpl_test_null(kmo_interpolate_vector_wcs(NULL, NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_frame *fr = cpl_frame_new();
    cpl_test_null(kmo_interpolate_vector_wcs(fr, NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    // empty frame
    cpl_vector *x_out = cpl_vector_new(100);
    cpl_test_null(kmo_interpolate_vector_wcs(fr, x_out));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    // not overlapping
    char *my_path = cpl_sprintf("%s/ref_data/kmos_atmos_k.fits", getenv("srcdir"));
    cpl_frame_set_filename(fr, my_path);
    cpl_free(my_path);
    cpl_frame_set_tag(fr, "gaga_tag");
    cpl_vector_fill(x_out, 0);
    cpl_test_null(kmo_interpolate_vector_wcs(fr, x_out));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    kmo_test_verbose_on();

    cpl_vector *solar_y = NULL;
    cpl_vector *solar_x = kmo_create_lambda_vec(2460, 1, 1.91, 0.000252033);
    cpl_test_nonnull(solar_y = kmo_interpolate_vector_wcs(fr, solar_x));
    cpl_test_error(CPL_ERROR_NONE);
kmclipm_vector *ddd = kmclipm_vector_create(solar_y);
    cpl_test_abs(0.793042, kmclipm_vector_get_mean(ddd), 0.001);

    cpl_frame_delete(fr);
    cpl_vector_delete(x_out);
    cpl_vector_delete(solar_x);
//    cpl_vector_delete(solar_y);
kmclipm_vector_delete(ddd);
}

/**
    @brief   Test for kmo_divide_blackbody()
 */
void test_kmo_divide_blackbody(void)
{
    kmo_test_verbose_off();
    // null inputs
    kmo_divide_blackbody(NULL, NULL, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    char *my_path = cpl_sprintf("%s/ref_data/kmos_atmos_k.fits", getenv("srcdir"));
kmclipm_vector *ddd = kmclipm_vector_load(my_path, 1);
cpl_free(my_path);
cpl_vector *solar_y = kmclipm_vector_create_non_rejected(ddd);
kmclipm_vector_delete(ddd);
    kmo_divide_blackbody(solar_y, NULL, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    // vectors of differing size
    cpl_vector *solar_x = kmo_create_lambda_vec(2460,
                                                1, 1.91, 0.000252033);
    kmo_divide_blackbody(solar_y, solar_x, -1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    // negative temperature
    cpl_vector_delete(solar_x);
    solar_x = kmo_create_lambda_vec(cpl_vector_get_size(solar_y),
                                    1, 1.91, 0.000252033);
    kmo_divide_blackbody(solar_y, solar_x, -1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    kmo_test_verbose_on();

ddd = kmclipm_vector_create(cpl_vector_duplicate(solar_y));
    cpl_test_abs(0.757868, kmclipm_vector_get_mean(ddd), 0.001);
kmclipm_vector_delete(ddd);
    kmo_divide_blackbody(solar_y, solar_x, 5300);
    cpl_test_error(CPL_ERROR_NONE);
ddd = kmclipm_vector_create(cpl_vector_duplicate(solar_y));
    cpl_test_abs(7.99304, kmclipm_vector_get_mean(ddd), 0.001);
kmclipm_vector_delete(ddd);
    cpl_vector_delete(solar_y);
    cpl_vector_delete(solar_x);
}

/**
    @brief   Test for kmo_remove_line()
 */
void test_kmo_remove_line(void)
{
    kmo_test_verbose_off();
    // null inputs
    kmo_remove_line(NULL, NULL, NULL, 2.1663, 0.015);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    char *my_path = cpl_sprintf("%s/ref_data/test_br_gamma.fits", getenv("srcdir"));
kmclipm_vector *ddd = kmclipm_vector_load(my_path, 0);
    cpl_free(my_path);
cpl_vector *data = cpl_vector_duplicate(ddd->data);
kmclipm_vector_delete(ddd);
    cpl_vector_fill(data, 1);
    kmo_remove_line(data, NULL, NULL, 2.1663, 0.015);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *lambda = kmo_create_lambda_vec(2460,
                                                1, 1.91, 0.000252033);
    kmo_remove_line(data, lambda, NULL, 2.1663, 0.015);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    my_path = cpl_sprintf("%s/ref_data/test_br_gamma.fits", getenv("srcdir"));
kmclipm_vector *aaa = kmclipm_vector_load(my_path, 1);
    cpl_free(my_path);
cpl_vector *atmos = kmclipm_vector_create_non_rejected(aaa);
kmclipm_vector_delete(aaa);
    kmo_remove_line(data, lambda, atmos, 2.1663, 0.015);
    cpl_test_error(CPL_ERROR_NONE);

    kmo_test_verbose_on();

    cpl_vector_delete(data);
    my_path = cpl_sprintf("%s/ref_data/test_br_gamma.fits", getenv("srcdir"));
kmclipm_vector *iii = kmclipm_vector_load(my_path, 0);
    cpl_free(my_path);
data = cpl_vector_duplicate(iii->data);
kmclipm_vector_delete(iii);
ddd = kmclipm_vector_create(cpl_vector_duplicate(data));
    cpl_test_abs(3.40152e+08, kmclipm_vector_get_mean(ddd), 1e5);
kmclipm_vector_delete(ddd);
    kmo_remove_line(data, lambda, atmos, 2.1663, 0.015);
    cpl_test_error(CPL_ERROR_NONE);
ddd = kmclipm_vector_create(cpl_vector_duplicate(data));
    cpl_test_abs(3.39914e+08, kmclipm_vector_get_mean(ddd), 1e5);
kmclipm_vector_delete(ddd);
    cpl_vector_delete(data);
    cpl_vector_delete(lambda);
    cpl_vector_delete(atmos);
}

/**
    @brief   Test for kmo_calc_counts()
 */
void test_kmo_calc_counts(void)
{
    double cnt1=0, cnt2=0;
    kmo_test_verbose_off();
    kmo_calc_counts(NULL, NULL, -1, -1, -1, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    char *my_path = cpl_sprintf("%s/ref_data/test_br_gamma.fits", getenv("srcdir"));
    kmclipm_vector *ddd = kmclipm_vector_load(my_path, 0);
    cpl_free(my_path);

    cpl_vector *data = cpl_vector_duplicate(ddd->data);
    kmclipm_vector_delete(ddd);

    kmo_calc_counts(data, NULL, -1, -1, -1, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    kmo_test_verbose_on();

    kmo_calc_counts(data, "K", -1, -1, -1, &cnt1, &cnt2);
    cpl_test_abs(0, cnt1, 0.01);
    cpl_test_abs(0, cnt2, 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    kmo_calc_counts(data, "K", 1, 1.9099999666214, 0.00025203253608197, &cnt1, &cnt2);
    cpl_test_abs(3.69643e+11, cnt1, 1e8);
    cpl_test_abs(0, cnt2, 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_error(CPL_ERROR_NONE);
    cpl_vector_delete(data);
}

/**
    @brief   Test for kmo_calc_zeropoint()
 */
void test_kmo_calc_zeropoint(void)
{
    cpl_test_abs(1, kmclipm_is_nan_or_inf(kmo_calc_zeropoint(-1, -1, -1, -1, 0.01, "H")),
                 0.01);
    cpl_test_abs(1, kmclipm_is_nan_or_inf(kmo_calc_zeropoint(-1, -1, 0, 0, 0.01, "H")),
                 0.01);

    cpl_test_abs(9.00082, kmo_calc_zeropoint(10, 0, 10, 0, 0.01, "H"), 0.01);

    cpl_test_error(CPL_ERROR_NONE);
}

/**
    @brief   Test for kmo_calc_throughput()
 */
void test_kmo_calc_throughput(void)
{
    kmo_test_verbose_off();
    cpl_test_abs(0, kmo_calc_throughput(-1, -1, -1, -1, -1, NULL), 1e-10);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_test_abs(0, kmo_calc_throughput(-1, -1, -1, -1, -1, "gaga"), 1e-10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    cpl_test_abs(0, kmo_calc_throughput(1000000, -1, -1, -1, -1, "K"), 1e-10);
    cpl_test_error(CPL_ERROR_DIVISION_BY_ZERO);
    kmo_test_verbose_on();

    cpl_test_abs(6.30531e-12, kmo_calc_throughput(-1, -1, -1, -1, -1, "K"), 1e-13);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_abs(4.01631, kmo_calc_throughput(8, -1, 1e8, -1, 1.6, "K"), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
    @brief   Test for kmo_calc_mean_throughput()
 */
void test_kmo_calc_mean_throughput(void)
{
    kmo_test_verbose_off();
    kmo_calc_mean_throughput(NULL, -1, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    double d[4] = {1, 2, 3, 4};
    kmo_calc_mean_throughput(d, -1, NULL, NULL);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    kmo_calc_mean_throughput(d, 4, NULL, NULL);
    cpl_test_error(CPL_ERROR_NONE);

    double mean = 0;
    kmo_calc_mean_throughput(d, 4, &mean, NULL);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(2.5, mean, 0.01);

    double stdev = 0;
    kmo_calc_mean_throughput(d, 4, &mean, &stdev);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(1.29099, stdev, 0.01);
}

/**
    @brief   Test for kmo_calculate_std_trace()
 */
void test_kmo_calculate_std_trace(void)
{
    kmo_test_verbose_off();
    kmo_calculate_std_trace(NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_imagelist *cube = cpl_imagelist_new();
    kmo_calculate_std_trace(cube, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    kmo_calculate_std_trace(cube, "gauss", NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    // no images in cube
    double stdtrace = 0;
    kmo_calculate_std_trace(cube, "gauss", &stdtrace);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    // add images
    cpl_image *img = cpl_image_new(50, 50, CPL_TYPE_FLOAT);
    cpl_image_fill_gaussian (img, 25, 25, 2, 5, 5);
    cpl_imagelist_set(cube, img, 0);
    kmo_calculate_std_trace(cube, "gauss", &stdtrace);
    cpl_test_abs(-1, stdtrace, 0.01);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();
    int i = 0;
    for (i = 1; i < 1500; i++) {
        cpl_imagelist_set(cube, cpl_image_duplicate(img), i);
    }
    img = cpl_image_new(50, 50, CPL_TYPE_FLOAT);
    cpl_image_fill_gaussian (img, 27, 27, 2, 5, 5);
    cpl_imagelist_set(cube, img, 1500);
    for (i = 1501; i < 2048; i++) {
        cpl_imagelist_set(cube, cpl_image_duplicate(img), i);
    }

    kmo_calculate_std_trace(cube, "gauss", &stdtrace);
    cpl_test_abs(2.82843, stdtrace, 0.01);

    cpl_test_error(CPL_ERROR_NONE);

    cpl_imagelist_delete(cube);
}

/**
 * @brief   Test of helper functions for kmo_std_star
 */
int main(void)
{
    cpl_test_init("<usd-help@eso.org>", CPL_MSG_WARNING);

    test_kmo_get_obj_sky_frame_table();
    test_kmo_collapse_object_sky_frame_table();
    test_kmo_interpolate_vector_wcs();
    test_kmo_divide_blackbody();
//    test_kmo_remove_line();
    test_kmo_calc_counts();
    test_kmo_calc_zeropoint();
    test_kmo_calc_throughput();
    test_kmo_calc_mean_throughput();
    test_kmo_calculate_std_trace();

    return cpl_test_end(0);
}

/** @} */
