/* $Id: fors_idp-test.c,v 1.0 2017-11-20 18:45:53 msalmist Exp $
 *
 * This file is part of the FORS Library
 * Copyright (C) 2002-2006 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: msalmist $
 * $Date: 2017-11-20 18:45:53 $
 * $Revision: 1.0 $
 * $Name: not supported by cvs2svn $
 */


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

#include <fors_dark_impl.h>
#include <fors_dfs.h>
#include <fors_utils.h>

#include <test_simulate.h>
#include <test.h>

#include <cpl.h>

#include <fs_test.h>

#include <string.h>

#include <fors_dfs_idp.h>
#include <fors_img_science_impl.h>

/**
 * @defgroup idp - Tests for the idp module
 */

/**@{*/


/**
 * @brief Internal utility functions
 */
const char *const FORS_PFITS_INSTRUME    = "INSTRUME";

const char * in_string_def = "default_val";

static void test_idp_basic_functionalities(){


	cpl_propertylist * l1 = cpl_propertylist_new();
	cpl_propertylist * l2 = cpl_propertylist_new();
	cpl_propertylist * l3 = cpl_propertylist_new();
	cpl_propertylist * raw = cpl_propertylist_new();

	const double in_double = 33.0;
	const char * in_string = "prop";
	const int in_int = 55;
	const int raw_int = 88;

	cpl_propertylist_append_string(l1, "l1-p1", in_string);
	cpl_propertylist_append_double(l2, "l2-p1", in_double);
	cpl_propertylist_append_int(l3, "l3-p1", in_int);
	cpl_propertylist_append_int(raw, "raw", raw_int);
	cpl_propertylist_append_int(l1, "raw", raw_int + 13);
	cpl_propertylist_append_int(l2, "raw", raw_int + 12);
	cpl_propertylist_append_int(l3, "raw", raw_int + 10);

	fors_dfs_idp_converter *  converter = fors_dfs_idp_converter_new();
	const char * comment_converter = "COMMENT1";
	fors_dfs_idp_converter_add_conversion(converter,"raw", "raw_out", NULL, NULL);
	fors_dfs_idp_converter_add_conversion(converter,"l1-p1", "out-p1", comment_converter, l1);
	fors_dfs_idp_converter_add_conversion(converter,"l2-p1", "out-p2", NULL, l2);
	fors_dfs_idp_converter_add_conversion(converter,"l3-p1", "out-p3", NULL, l3);
	fors_dfs_idp_converter_add_conversion(converter,"no_source2", "should_not_be_there", NULL, l1);

	const cpl_boolean def_bool = CPL_TRUE;
	const double def_double = 66.0;
	const char * def_string = "def_string_val";
	const int def_int = 88;

	const char * comment_default = "COMMENT11";

	fors_dfs_idp_converter_add_boolean_default(converter, "def_boolean", comment_default, def_bool);
	fors_dfs_idp_converter_add_real_default(converter, "def_double", NULL, def_double);
	fors_dfs_idp_converter_add_string_default(converter, "def_string", NULL, def_string);
	fors_dfs_idp_converter_add_int_default(converter, "def_int", NULL, def_int);

	cpl_propertylist * out =
			fors_dfs_idp_converter_generate_idp_propertylist(converter, raw);

	const int out_raw_override = cpl_propertylist_get_int(out, "raw_out");
	test_eq(out_raw_override, raw_int);

	const double out_double = cpl_propertylist_get_double(out, "out-p2");
	test_rel(out_double, in_double, 1e-10);

	const char * out_string = cpl_propertylist_get_string(out, "out-p1");
	test_eq(strcmp(out_string, in_string), 0);
	const char * out_comment = cpl_propertylist_get_comment(out, "out-p1");
	test_eq(strcmp(out_comment, comment_converter), 0);

	const int out_int = cpl_propertylist_get_int(out, "out-p3");
	test_eq(out_int, in_int);

	test(!cpl_propertylist_has(out, "should_not_be_there"));

	const double out_def_double = cpl_propertylist_get_double(out, "def_double");
	test_rel(out_def_double, def_double, 1e-10);

	const cpl_boolean out_def_bool = cpl_propertylist_get_bool(out, "def_boolean");
	const char * out_def_comment = cpl_propertylist_get_comment(out, "def_boolean");
	test_eq(out_def_bool, def_bool);
	test_eq(strcmp(out_def_comment, comment_default), 0);


	const char * out_def_str = cpl_propertylist_get_string(out, "def_string");
	test_eq(strcmp(out_def_str, def_string), 0);

	const int out_def_int = cpl_propertylist_get_int(out, "def_int");
	test_eq(out_def_int, out_def_int);

	cpl_propertylist_delete(l1);
	cpl_propertylist_delete(l2);
	cpl_propertylist_delete(l3);
	cpl_propertylist_delete(raw);
	cpl_propertylist_delete(out);
	fors_dfs_idp_converter_delete(converter);
}

void test_idp_science_imaging(void){

	const char * sci_raw_fname = "science_raw_file.fits";

	cpl_propertylist * raw_plist = cpl_propertylist_new();
	cpl_propertylist * phot_plist = cpl_propertylist_new();
	cpl_propertylist * master_bias_plist = cpl_propertylist_new();

	const double bias_ron = 155.0;
	const char * filt_name = "filter_name_VALUE";
	const double win1_dit1 = 86400.0 * 2.0;

	const char * obs_prog_id = "kfuiof";
	const int obs_id = 22;

	const double mjd_obs = 2200.0;
	const double exptime = win1_dit1;

	const double mjd_end_expected = mjd_obs + exptime / 86400.0;

	const char * pro_tech_val = "pro.tech.from.eso";

	const double ra_val = 50;
	const double dec_val = 70;

	const double zp = 33;
	const double zp_err = .12;

	const char * version = "fors2/all_versions";

	cpl_propertylist_append_string(raw_plist, "ESO PRO REC1 PIPE ID", version);
	cpl_propertylist_append_string(raw_plist, "ESO PRO REC1 RAW1 NAME", sci_raw_fname);
	cpl_propertylist_append_double(raw_plist, "ESO QC RON", bias_ron + 40.0);
	cpl_propertylist_append_double(raw_plist, "MJD-OBS", mjd_obs);
	cpl_propertylist_append_string(raw_plist, "ESO INS FILT1 NAME", filt_name);
	cpl_propertylist_append_double(raw_plist, "ESO DET WIN1 DIT1", win1_dit1);
	cpl_propertylist_append_string(raw_plist, "ESO OBS PROG ID", obs_prog_id);
	cpl_propertylist_append_int(raw_plist, "ESO OBS ID", obs_id);
	cpl_propertylist_append_string(raw_plist, "ESO PRO TECH", pro_tech_val);
	cpl_propertylist_append_double(raw_plist, "RA", ra_val);
	cpl_propertylist_append_double(raw_plist, "DEC", dec_val);
	cpl_propertylist_append_double(raw_plist, "ESO QC INSTRUMENT ZEROPOINT", zp + 1.0);
	cpl_propertylist_append_double(raw_plist, "ESO QC INSTRUMENT ZEROPOINT ERROR", zp_err + 1.0);

	cpl_propertylist_append_double(phot_plist, "ESO QC RON", bias_ron + 10.0);
	cpl_propertylist_append_string(phot_plist, "ESO INS FILT1 NAME", "none1");
	cpl_propertylist_append_double(phot_plist, "ESO DET WIN1 DIT1", win1_dit1 + 2.0);
	cpl_propertylist_append_double(phot_plist, "ESO QC INSTRUMENT ZEROPOINT", zp);
	cpl_propertylist_append_double(phot_plist, "ESO QC INSTRUMENT ZEROPOINT ERROR", zp_err);

	cpl_propertylist_append_double(master_bias_plist, "ESO QC RON", bias_ron);
	cpl_propertylist_append_string(master_bias_plist, "ESO INS FILT1 NAME", "none2");
	cpl_propertylist_append_double(master_bias_plist, "ESO DET WIN1 DIT1", win1_dit1 + 3.0);
	cpl_propertylist_append_double(master_bias_plist, "ESO QC INSTRUMENT ZEROPOINT", zp + 11.0);
	cpl_propertylist_append_double(master_bias_plist, "ESO QC INSTRUMENT ZEROPOINT ERROR", zp_err + 11.0);

	const double min_data = -30.0;
	const double max_data = 30.0;

	cpl_image * data = cpl_image_new(30, 40, CPL_TYPE_FLOAT);
	cpl_image * data_w = cpl_image_new(30, 40, CPL_TYPE_FLOAT);

	cpl_image_set(data, 1, 1, min_data);
	cpl_image_set(data, 1, 6, max_data);

	fors_image * img = fors_image_new(data, data_w);

	fors_dfs_idp_converter * conv =
			fors_generate_imaging_idp_converter(master_bias_plist, phot_plist, img);

	cpl_propertylist * result =
			fors_dfs_idp_converter_generate_idp_propertylist(conv, raw_plist);

	fors_dfs_idp_converter_delete(conv);

	const double detron = cpl_propertylist_get_double(result, "DETRON");
	const double effron = cpl_propertylist_get_double(result, "EFFRON");

	test_rel(detron, bias_ron, 1e-10);
	test_rel(effron, bias_ron, 1e-10);

	const double dmin = cpl_propertylist_get_double(result, "DATAMIN");
	const double dmax = cpl_propertylist_get_double(result, "DATAMAX");

	test_rel(dmin, min_data, 1e-10);
	test_rel(dmax, max_data, 1e-10);

	const char * filt_data = cpl_propertylist_get_string(result, "FILTER");
	test_eq(strcmp(filt_data, filt_name), 0);

	const double dit1 = cpl_propertylist_get_double(result, "DIT");
	const double dit2 = cpl_propertylist_get_double(result, "TEXPTIME");
	test_rel(dit1, win1_dit1, 1e-10);
	test_rel(dit2, win1_dit1, 1e-10);

	const char * prog_id = cpl_propertylist_get_string(result, "PROG_ID");
	test_eq(strcmp(prog_id, obs_prog_id), 0);

	const int obid1 = cpl_propertylist_get_int(result, "OBID1");
	test_eq(obid1, obs_id);

	const double mjd_end = cpl_propertylist_get_double(result, "MJD-END");
	test_rel(mjd_end, mjd_end_expected, 1e-10);

	const bool epoch = cpl_propertylist_get_bool(result, "M_EPOCH");
	const bool single_exp = cpl_propertylist_get_bool(result, "SINGLEXP");

	test(!epoch);
	test(single_exp);

	const int ncombine = cpl_propertylist_get_int(result, "NCOMBINE");
	test_eq(ncombine, 1);

	const char * obstech = cpl_propertylist_get_string(result, "OBSTECH");
	test_eq(strcmp(obstech, pro_tech_val), 0);

	const char * fluxcal = cpl_propertylist_get_string(result, "FLUXCAL");
	test_eq(strcmp(fluxcal, "ABSOLUTE"), 0);

	const char * procsoft = cpl_propertylist_get_string(result, "PROCSOFT");
	test_eq(strcmp(procsoft, version), 0);

	const char * referenc = cpl_propertylist_get_string(result, "REFERENC");
	test_eq(strlen(referenc), 0);

	const char * prodcat = cpl_propertylist_get_string(result, "PRODCATG");
	test_eq(strcmp(prodcat, "SCIENCE.IMAGE"), 0);

	const char * prov1 = cpl_propertylist_get_string(result, "PROV1");
	test_eq(strcmp(prov1, sci_raw_fname), 0);

	const char * bunit = cpl_propertylist_get_string(result, "BUNIT");
	test_eq(strcmp(bunit, "adu"), 0);

	const int weight = cpl_propertylist_get_int(result, "WEIGHT");
	test_eq(weight, 1);

	const char* cunit1 = cpl_propertylist_get_string(result, "CUNIT1");
	const char* cunit2 = cpl_propertylist_get_string(result, "CUNIT2");

	test_eq(strcmp(cunit1, cunit2), 0);
	test_eq(strcmp(cunit1, "deg"), 0);

	const bool apmatchd = cpl_propertylist_get_bool(result, "APMATCHD");
	test(!apmatchd);

	const double fpra = cpl_propertylist_get_double(result, "FPRA");
	const double fpde = cpl_propertylist_get_double(result, "FPDE");

	test_rel(fpra, ra_val, 1e-10);
	test_rel(fpde, dec_val, 1e-10);

	const double phot_zp = cpl_propertylist_get_double(result, "PHOTZP");
	const double phot_zp_err = cpl_propertylist_get_double(result, "PHOTZPER");

	cpl_test_rel(phot_zp, zp, 1e-10);
	cpl_test_rel(phot_zp_err, zp_err, 1e-10);

	const char* psys = cpl_propertylist_get_string(result, "PHOTSYS");
	test_eq(strcmp(psys, "VEGA"), 0);

	const double csyer1 = cpl_propertylist_get_double(result, "CSYER1");
	test_rel(csyer1, 5.0, 1e-10);

	cpl_propertylist_delete(result);

	cpl_propertylist_delete(raw_plist);
	cpl_propertylist_delete(phot_plist);
	cpl_propertylist_delete(master_bias_plist);
	fors_image_delete(&img);

	test_eq(cpl_error_get_code(), CPL_ERROR_NONE);
}

/**
 * @brief   Test of idp module
 */
int main(void)
{
    TEST_INIT;

   // test_idp_basic_functionalities();
   // test_idp_science_imaging();

    TEST_END;
}

/**@}*/
