/*
 * This file is part of the ESO SINFONI Pipeline
 * Copyright (C) 2004,2005 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, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
 */
/*----------------------------------------------------------------------------

 File name    :       sinfo_new_cubes_build.c
 Author       :    J. Schreiber
 Created on   :    December 3, 2003
 Description  :    Creates data cubes or merges data cubes
 out of jittered object-sky
 nodding observations
 ---------------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

/*----------------------------------------------------------------------------
 Includes
 ---------------------------------------------------------------------------*/
#include "sinfo_new_cubes_build.h"
#include "sinfo_pfits.h"
#include "sinfo_msg.h"
#include "sinfo_pro_save.h"
#include "sinfo_objnod_ini_by_cpl.h"
#include "sinfo_functions.h"
#include "sinfo_hidden.h"
#include "sinfo_utilities_scired.h"
#include "sinfo_wave_calibration.h"
#include "sinfo_cube_construct.h"
#include "sinfo_skycor.h"
#include "sinfo_product_config.h"
#include "sinfo_error.h"
#include "sinfo_utils_wrappers.h"
#include "sinfo_atmo_disp.h"
/*----------------------------------------------------------------------------
 Defines
 ---------------------------------------------------------------------------*/
#define PI_NUMB        (3.1415926535897932384626433832795) /* pi */

static void
sinfo_atm_correction(cpl_imagelist** ppCube, cpl_frameset* sof,
                     const char* polyshiftname, double dis_cube,
                     double centralLambda_cube, int centralpix_cube);

/*----------------------------------------------------------------------------
 Function Definitions
 ---------------------------------------------------------------------------*/
/* Temporally commented out as not used
 static cpl_image*
 sinfo_flux_corr(const cpl_image* inp,const cpl_image* wav,const double dis);
 */
/**@{*/
/**
 * @addtogroup sinfo_rec_jitter Cube construction
 *
 * TBD
 */

/*----------------------------------------------------------------------------
 Function     : sinfo_new_cubes_build()
 In           : ini_file: file name of according .ini file
 Out          : integer (0 if it worked, -1 if it doesn't)
 Job          : this routine carries through the data cube creation of an
 object science observation using object-sky nodding
 and jittering. This script expects jittered frames that
 were already sky-subtracted
 averaged, flatfielded, spectral tilt corrected and
 interleaved if necessary
 ---------------------------------------------------------------------------*/
int
sinfo_new_cubes_build(const char* plugin_id, cpl_parameterlist* config,
                      cpl_frameset* sof, const char* procatg,
                      const int frame_index)
{

    object_config * cfg = NULL;
    cpl_image * im = NULL;
    cpl_image * wavemapim = NULL;
    cpl_image * wim = NULL;
    cpl_image * res_obj = NULL;
    cpl_image * calim = NULL;
    cpl_image * halospec = NULL;
    cpl_image * sky_im = NULL;
    cpl_image* res_ima = NULL;
    cpl_image* res_wim = NULL;
    cpl_image* res_flat = NULL;
    cpl_image* res_sky = NULL;
    cpl_image* flat_im = NULL;
    cpl_image* eima_avg = NULL;
    cpl_image* eima_med = NULL;
    cpl_imagelist * cube = NULL;
    cpl_imagelist * outcube = NULL;
    cpl_imagelist * outcube2 = NULL;
    cpl_imagelist* cflat = NULL;
    cpl_imagelist* cflat2 = NULL;
    cpl_imagelist* csky = NULL;
    cpl_imagelist* csky2 = NULL;
    cpl_propertylist* plist = NULL;
    cpl_frame* obj_frm = NULL;
    cpl_frame* sky_frm = NULL;
    cpl_imagelist* obj_cor = NULL;

    int sky_cor = 0;
    int flux_cor = 0;
    int n = 0;
    int cpix = 0;
    float mi = 0;
    float ma = 0;
    float fcol = 0;
    float center_x = 0;
    float center_y = 0;
    float * correct_dist = NULL;
    float * distances = NULL;
    float ** slit_edges = NULL;
    int nx = 0;
    int ny = 0;
    cpl_image* dif = NULL;
    float* pd = NULL;
    float* pw = NULL;
    int i = 0;
    int j = 0;

    double dis = 0;
    double cwav = 0;

    char pro_mjit[MAX_NAME_SIZE];
    char pro_obs[MAX_NAME_SIZE];
    char pro_med[MAX_NAME_SIZE];

    char * name = NULL;
    char file_name[FILE_NAME_SZ];

    cpl_table* qclog_tbl = NULL;
    cpl_frameset* stk = NULL;
    cpl_parameter* p = NULL;
    int pdensity = 0;
    sinfo_skycor_qc* sqc = NULL;
    cpl_table* int_obj = NULL;

    check_nomsg(p = cpl_parameterlist_find(config, "sinfoni.product.density"));
    check_nomsg(pdensity = cpl_parameter_get_int(p));

    if (strcmp(procatg, PRO_COADD_STD) == 0) {
        strcpy(pro_mjit, PRO_MASK_COADD_STD);
        strcpy(pro_obs, PRO_OBS_STD);
        strcpy(pro_med, PRO_MED_COADD_STD);

    }
    else if (strcmp(procatg, PRO_COADD_PSF) == 0) {
        strcpy(pro_mjit, PRO_MASK_COADD_PSF);
        strcpy(pro_obs, PRO_OBS_PSF);
        strcpy(pro_med, PRO_MED_COADD_PSF);
    }
    else {
        strcpy(pro_mjit, PRO_MASK_COADD_OBJ);
        strcpy(pro_obs, PRO_OBS_OBJ);
        strcpy(pro_med, PRO_MED_COADD_OBJ);
    }

    /*----parse input data and parameters to set cube_config cfg---*/
    check_nomsg(stk = cpl_frameset_new());

    cknull(cfg = sinfo_parse_cpl_input_objnod(config, sof, &stk),
           "Error setting parameter configuration");

    ck0(sinfo_check_input_data(cfg), "error checking input");

    check_nomsg(p = cpl_parameterlist_find(config, "sinfoni.objnod.fcol"));
    check_nomsg(fcol = (float )cpl_parameter_get_double(p));

    for (n = 0; n < cfg->nframes; n++) {

        sinfo_msg_debug("Read FITS information");
        name = cfg->framelist[n];
        if (sinfo_is_fits_file(name) != 1) {
            sinfo_msg_error("Input file %s is not FITS", name);
            goto cleanup;
        }

        sinfo_msg_debug("frame no.: %d, name: %s\n", n, name);
        cknull(im = cpl_image_load(name,CPL_TYPE_FLOAT,0,0),
               " could not load frame %s!",name);

        /*
         *--------------------------------------------------------------
         *---------------------RESAMPLING-------------------------------
         *--------------------------------------------------------------
         */
        sinfo_msg("Resampling object");
        cknull(wavemapim = cpl_image_load(cfg->wavemap, CPL_TYPE_FLOAT, 0, 0),
               "could not load wavemap");
        check_nomsg(wim = cpl_image_duplicate(wavemapim));

        check_nomsg(
                        p = cpl_parameterlist_find(config,
                                        "sinfoni.objnod.flux_cor"));
        check_nomsg(flux_cor = cpl_parameter_get_bool(p));

        nx = cpl_image_get_size_x(wim);
        ny = cpl_image_get_size_y(wim);
        /*
         check_nomsg(pd=cpl_image_get_data(im));
         //To compare statistics we make sure that the input image has all 1s

         for(i=0;i<nx;i++) {
         for(j=0;j<ny;j++) {
         pd[nx*j+i]=1.;
         }
         }
         cpl_image_save(im,"im.fits", CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
         */

        cknull(res_ima = sinfo_new_defined_resampling(im,
                        wim,
                        cfg->ncoeffs,
                        &cfg->nrows,
                        &dis,
                        &mi,
                        &ma,
                        &cwav,
                        &cpix),
               " sinfo_definedResampling() failed" );

        //cpl_image_save(res_ima,"res_im.fits",
        //CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);

        //We create an image with the derivatives
        check_nomsg(dif = cpl_image_new(nx, ny, CPL_TYPE_FLOAT));
        pw = cpl_image_get_data(wim);
        pd = cpl_image_get_data(dif);

        for (i = 1; i < nx - 1; i++) {
            for (j = 1; j < ny - 1; j++) {
                if (!isnan(pd[nx*j+i])) {
                    pd[nx * j + i] = 2.0 * dis
                                    / (pw[nx * (j + 1) + i]
                                          - pw[nx * (j - 1) + i]);
                }
            }
            if (!isnan(pd[i])) {
                pd[i] = dis / (pw[nx + i] - pw[i]);
            }
            if (!isnan(pd[nx*(ny-1)+i])) {
                pd[nx * (ny - 1) + i] =
                                dis
                                / (pw[nx * (ny - 1) + i]
                                      - pw[nx
                                           * (ny
                                                           - 2)
                                                           + i]);
            }
        }
    
        //cpl_image_save(dif,"diff.fits",
        //CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);

        cknull(res_wim = sinfo_new_defined_resampling(dif,
                        wim,
                        cfg->ncoeffs,
                        &cfg->nrows,
                        &dis,
                        &mi,
                        &ma,
                        &cwav,
                        &cpix),
               " sinfo_definedResampling() failed" );

        cpl_image_delete(dif);
        //cpl_image_save(res_wim,"res_diff.fits",
        //CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);

        //To rescale in flux we divide the resampled image and
        //the resampled derivatives. At this point res_obj should have same
        //flux as input image (im.diff)

        res_obj = cpl_image_duplicate(res_ima);
        sinfo_free_image(&res_ima);
        if (flux_cor) {
            sinfo_msg("Apply flux correction");
            cpl_image_divide(res_obj, res_wim);
        }
        //cpl_image_save(res_obj,"res_obj.fits",
        //CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);

        sinfo_free_image(&wim);

        if ((pdensity == 3) || (pdensity == 2 && frame_index == 0)) {
            snprintf(file_name, MAX_NAME_SIZE - 1, "%s%d%s",
                            RESAMPLED_OUT_OBJ_FILENAME, frame_index, ".fits");
            ck0(
                            sinfo_pro_save_ima(res_obj,sof,sof,file_name, PRO_RESAMPLED_OBJ, qclog_tbl,plugin_id,config),
                            "cannot save image %s", file_name);
        }

        if (strcmp(cfg->sky_dist, "no_sky") != 0) {
            sinfo_msg("Resampling sky");
            check_nomsg(
                            sky_im = cpl_image_load(cfg->sky_dist,
                                            CPL_TYPE_FLOAT, 0, 0));
            check_nomsg(wim = cpl_image_duplicate(wavemapim));
            cknull(
                            res_ima = sinfo_new_defined_resampling(sky_im, wim,
                                            cfg->ncoeffs, &cfg->nrows, &dis,
                                            &mi, &ma, &cwav, &cpix),
                                            " sinfo_definedResampling() failed");
            res_sky = cpl_image_duplicate(res_ima);
            sinfo_free_image(&res_ima);
            if (flux_cor) {
                sinfo_msg("Apply flux correction");
                cpl_image_divide(res_sky, res_wim);
            }

            sinfo_free_image(&wim);
            sinfo_free_image(&sky_im);
            if ((pdensity == 3) || (pdensity == 2 && frame_index == 0)) {

                snprintf(file_name, MAX_NAME_SIZE - 1, "%s%d%s",
                                RESAMPLED_OUT_SKY_FILENAME, frame_index,
                                ".fits");
                ck0(
                                sinfo_pro_save_ima(res_sky,sof,sof,file_name, PRO_RESAMPLED_SKY, qclog_tbl,plugin_id,config),
                                "cannot save image %s", file_name);
            }

        }

        if (n == 0) {
            if (strcmp(cfg->mflat_dist, "not_found") != 0) {
                sinfo_msg("Resampling master flat");
                cknull(
                                flat_im = cpl_image_load(cfg->mflat_dist,
                                                CPL_TYPE_FLOAT, 0, 0),
                                                "Distorted master flat field not found\n"
                                                "You may have set --stack-flat_ind=FALSE\n"
                                                "Flat field resampling skipped");
                check_nomsg(wim = cpl_image_duplicate(wavemapim));
                cknull(res_ima = sinfo_new_defined_resampling(flat_im,
                                wim,
                                cfg->ncoeffs,
                                &cfg->nrows,
                                &dis,
                                &mi,
                                &ma,
                                &cwav,
                                &cpix),
                       " sinfo_definedResampling() failed" );

                res_flat = cpl_image_duplicate(res_ima);
                sinfo_free_image(&res_ima);
                if (flux_cor) {
                    sinfo_msg("Apply flux correction");
                    cpl_image_divide(res_flat, res_wim);
                }
                sinfo_free_image(&wim);
                sinfo_free_image(&flat_im);
                if ((pdensity == 3) || (pdensity == 2 && frame_index == 0)) {
                    snprintf(file_name, MAX_NAME_SIZE - 1, "%s%d%s",
                                    RESAMPLED_OUT_FLAT_FILENAME, frame_index,
                                    ".fits");
                    ck0(
                                    sinfo_pro_save_ima(res_flat,sof,sof,file_name, PRO_RESAMPLED_FLAT_LAMP, qclog_tbl,plugin_id,config),
                                    "cannot save image %s", file_name);
                }

            }

        }

        sinfo_msg("wmin %f wmax %f wcent %f wstep %f cpix %d", mi, ma, cwav,
                  dis, cpix);
        sinfo_free_image(&res_wim);
        sinfo_free_image(&im);
        sinfo_free_image(&wavemapim);

        /*
         *-------------------------------------------------------------------
         *----------------Calibration----------------------------------------
         *-------------------------------------------------------------------
         */
        /*----Multiply with calibrated halogen lamp spectrum----*/
        if (cfg->halocorrectInd == 1) {
            sinfo_msg("Calibration");
            check_nomsg(halospec = cpl_image_load(cfg->halospectrum,
                            CPL_TYPE_FLOAT,0,0));

            cknull(calim = sinfo_new_multiply_image_with_spectrum(res_obj,
                            halospec),
                   " sinfo_new_multiply_image_with_spectrum() failed" );

            sinfo_free_image(&halospec);
            sinfo_free_image(&res_obj);
            res_obj = cpl_image_duplicate(calim);
            sinfo_free_image(&calim);
        }

        /*
         *-------------------------------------------------------------------
         *------------------CUBECREATION-------------------------------------
         *-------------------------------------------------------------------
         */
        sinfo_msg("Cube creation");
        /*---select north-south-test or fitting of slitlet edges--*/
        if (cfg->northsouthInd == 0) {
            sinfo_msg("cfg->northsouthInd == 0");
            cknull(
                            slit_edges = sinfo_read_slitlets_edges(cfg->nslits,
                                            cfg->poslist),
                                            "error reading slitlets edges");
        }
        else {
            sinfo_msg("cfg->northsouthInd != 0");
            cknull(distances = sinfo_read_distances(cfg->nslits, cfg->distlist),
                   "error reading distances");
        }

        cknull(correct_dist = (float*) cpl_calloc(cfg->nslits, sizeof (float)),
               " could not allocate memory!");

        sinfo_msg("Create cube object");
        if (cfg->northsouthInd == 0) {

            cknull(cube = sinfo_new_make_cube_spi(res_obj,slit_edges,
                            correct_dist),
                            "could not construct data cube!");

        }
        else {
            cknull(cube = sinfo_new_make_cube_dist(res_obj,fcol,distances,
                            correct_dist),
                            "could not construct a data cube!");
        }
        sinfo_free_image(&res_obj);

        if (strcmp(cfg->sky_dist, "no_sky") != 0) {

            sinfo_msg("Create cube sky");
            if (cfg->northsouthInd == 0) {
                cknull(csky = sinfo_new_make_cube_spi(res_sky,slit_edges,
                                correct_dist),
                                "could not construct data cube!");
            }
            else {
                cknull(csky = sinfo_new_make_cube_dist(res_sky,fcol,distances,
                                correct_dist),
                                "could not construct a data cube!");
            }
            sinfo_free_image(&res_sky);
        }

        if (n == 0) {
            if (strcmp(cfg->mflat_dist, "not_found") != 0) {
                sinfo_msg("Create cube master flat");
                if (cfg->northsouthInd == 0) {
                    cknull(cflat=sinfo_new_make_cube_spi(res_flat,slit_edges,
                                    correct_dist),
                                    "could not construct data cube!");
                }
                else {
                    cknull(cflat = sinfo_new_make_cube_dist(res_flat,fcol,distances,
                                    correct_dist),
                                    "could not construct a data cube!");
                }
                sinfo_free_image(&res_flat);
            }
        }

        if (cfg->northsouthInd == 0) {
            sinfo_new_destroy_2Dfloatarray(&slit_edges, cfg->nslits);
        }
        else {
            sinfo_new_destroy_array(&distances);
        }

        /*
         *--------------------------------------------------------------------
         *------------------------FINETUNING----------------------------------
         *--------------------------------------------------------------------
         * shift the rows of the reconstructed images of the data cube to the
         * correct sub pixel position select the shift method: polynomial
         * interpolation, FFT or cubic spline interpolation
         *--------------------------------------------------------------------
         */

        if (strcmp(cfg->sky_dist, "no_sky") != 0) {
            if (pdensity > 0) {
                cknull(csky2=sinfo_new_fine_tune(csky,
                                correct_dist,
                                cfg->method,
                                cfg->order,
                                cfg->nslits),
                                " could not fine tune the data cube");

                sinfo_free_imagelist(&csky);
                sinfo_msg("Stretch output cube along Y direction");

                cknull(csky = sinfo_new_bin_cube(csky2, 1, 2, 0, 63, 0, 63),
                       "error rebinning sky cube");
                sinfo_free_imagelist(&csky2);

                snprintf(file_name, MAX_NAME_SIZE - 1, "%s%2.2d%s", "out_sky_cube",
                         frame_index, ".fits");
                ck0(
                                sinfo_pro_save_ims(csky,sof,sof,file_name, PRO_OBS_SKY,NULL,plugin_id,config),
                                "cannot dump cube %s", file_name);
                cknull(eima_med = sinfo_new_median_cube(csky),
                       "Creating an average image");
                check_nomsg(center_x = cpl_image_get_size_x(eima_med) / 2. + 0.5);
                check_nomsg(center_y = cpl_image_get_size_y(eima_med) / 2. + 0.5);

                sinfo_new_set_wcs_cube(csky, file_name, cwav, dis, cpix, center_x,
                                       center_y);

                sinfo_free_imagelist(&csky);

                snprintf(file_name, MAX_NAME_SIZE - 1, "%s%2.2d%s", "out_sky_med",
                         frame_index, ".fits");
                ck0(
                                sinfo_pro_save_ima(eima_med,sof,sof,file_name, PRO_SKY_MED,NULL,plugin_id,config),
                                "cannot save ima %s", file_name);

                check_nomsg(
                                sinfo_new_set_wcs_image(eima_med, file_name,
                                                center_x, center_y));
                sinfo_free_image(&eima_med);
            }
        }

        if (n == 0) {
            if (strcmp(cfg->mflat_dist, "not_found") != 0) {
                if (pdensity > 1) {
                    cknull(cflat2=sinfo_new_fine_tune(cflat,
                                    correct_dist,
                                    cfg->method,
                                    cfg->order,
                                    cfg->nslits),
                                    " could not fine tune the data cube");

                    sinfo_free_imagelist(&cflat);
                    sinfo_msg("Stretch output cube along Y direction");

                    cknull(cflat = sinfo_new_bin_cube(cflat2, 1, 2, 0, 63, 0, 63),
                           "Error binning flat cube");
                    sinfo_free_imagelist(&cflat2);

                    ck0(
                                    sinfo_pro_save_ims(cflat,sof,sof,OBJNOD_OUT_MFLAT_CUBE_FILENAME, PRO_MFLAT_CUBE,NULL,plugin_id,config),
                                    "cannot save cube %s",
                                    OBJNOD_OUT_MFLAT_CUBE_FILENAME);

                    sinfo_new_set_wcs_cube(cflat, OBJNOD_OUT_MFLAT_CUBE_FILENAME,
                                           cwav, dis, cpix, center_x, center_y);

                    cknull(eima_avg = sinfo_new_average_cube_to_image(cflat),
                           "Creating an average image");

                    ck0(
                                    sinfo_pro_save_ima(eima_avg,sof,sof,"out_mflat_avg.fits", "MFLAT_AVG",NULL,plugin_id,config),
                                    "cannot save ima %s", "out_mflat_avg.fits");

                    sinfo_free_image(&eima_avg);

                    cknull(eima_med = sinfo_new_median_cube(cflat),
                           "Error computing median on cube flat");

                    ck0(
                                    sinfo_pro_save_ima(eima_med,sof,sof,"out_mflat_med.fits", "MFLAT_MED",NULL,plugin_id,config),
                                    "cannot save ima %s", "out_mflat_med.fits");

                    sinfo_free_imagelist(&cflat);
                    sinfo_free_image(&eima_med);
                }
            }
        }

        cknull(outcube2=sinfo_new_fine_tune(cube,
                        correct_dist,
                        cfg->method,
                        cfg->order,
                        cfg->nslits),
               " could not fine tune the data cube");

        sinfo_msg("Stretch output cube along Y direction");
        cknull(outcube = sinfo_new_bin_cube(outcube2, 1, 2, 0, 63, 0, 63),
               "Error binning cube");
        sinfo_free_imagelist(&cube);
        cknull_nomsg(qclog_tbl = sinfo_qclog_init());
        sinfo_get_pupil_shift(outcube, n, &qclog_tbl);
        snprintf(file_name, MAX_NAME_SIZE - 1, "%s%2.2d%s", "out_cube_obj",
                 frame_index, ".fits");

        check_nomsg(center_x = cpl_image_get_size_x(
                        cpl_imagelist_get(outcube,0))/2.+0.5);
        check_nomsg(
                        center_y = cpl_image_get_size_y(cpl_imagelist_get(outcube, 0))
                        / 2. + 0.5);

        /*----------- atmospheric correction --------------*/
        if (cfg->polyshiftname && strlen(cfg->polyshiftname)) {
            sinfo_atm_correction(&outcube, sof, cfg->polyshiftname, dis, cwav, cpix);
        }
        /*-------------------------------------------------*/

        ck0(
                        sinfo_pro_save_ims(outcube, sof, sof, file_name, pro_obs,
                                        qclog_tbl, plugin_id, config),
                                        "cannot save cube %s", file_name);

        sinfo_new_set_wcs_cube(outcube, file_name, cwav, dis, cpix, center_x, center_y);
        /* free memory */
        /* to prevent error message comment next line */

        check_nomsg(p = cpl_parameterlist_find(config, "sinfoni.objnod.sky_cor"));

        check_nomsg(sky_cor = cpl_parameter_get_bool(p));
        if (sky_cor == 1 && (pdensity == 1 || pdensity == 3)
                        && strcmp(cfg->sky_dist, "no_sky") != 0) {
            obj_frm = cpl_frameset_find(sof, pro_obs);
            sky_frm = cpl_frameset_find(sof, PRO_OBS_SKY);
            sqc = sinfo_skycor_qc_new();
            ck0(sinfo_skycor(config, obj_frm, sky_frm, sqc, &obj_cor, &int_obj),
                "determining sky residuals corrected object");
            cpl_frameset_erase(sof, pro_obs);
            snprintf(file_name, MAX_NAME_SIZE - 1, "%s%2.2d%s", "out_cube_obj_cor",
                     frame_index, ".fits");
            ck0_nomsg(
                            sinfo_qclog_add_int(qclog_tbl, "QC SKYCOR THBKGFIT",
                                            sqc->th_fit,
                                            "Thermal background fit success", "%d"));

            ck0(
                            sinfo_pro_save_ims(obj_cor, sof, sof, file_name, pro_obs,
                                            qclog_tbl, plugin_id, config),
                                            "cannot save cube %s", file_name);

            sinfo_skycor_qc_delete(&sqc);

            sinfo_new_set_wcs_cube(obj_cor, file_name, cwav, dis, cpix, center_x,
                                   center_y);

            sinfo_free_imagelist(&obj_cor);
            snprintf(file_name, MAX_NAME_SIZE - 1, "%s%2.2d%s", "out_int_obj",
                     frame_index, ".fits");

            ck0(
                            sinfo_pro_save_tbl(int_obj,sof,sof,file_name, PRO_SPECTRA_QC,qclog_tbl,plugin_id,config),
                            "cannot save cube %s", file_name);
            sinfo_free_table(&int_obj);
        }
        sinfo_free_table(&qclog_tbl);
        sinfo_free_imagelist(&outcube2);
        sinfo_free_imagelist(&outcube);
        sinfo_free_float(&correct_dist);

    } /* end loop over n (nframes) */

    /* free memory */
    sinfo_objnod_free(&cfg);
    sinfo_free_frameset(&stk);

    return 0;

    cleanup: sinfo_skycor_qc_delete(&sqc);
    sinfo_free_imagelist(&obj_cor);
    sinfo_free_propertylist(&plist);
    sinfo_free_imagelist(&outcube2);
    sinfo_free_imagelist(&outcube);
    sinfo_free_table(&qclog_tbl);
    sinfo_free_image(&eima_avg);
    sinfo_free_image(&eima_med);
    sinfo_free_imagelist(&cflat);
    sinfo_free_imagelist(&cflat2);
    sinfo_free_imagelist(&cube);
    sinfo_free_imagelist(&csky);
    sinfo_free_imagelist(&csky2);

    if (cfg != NULL ) {
        if (cfg->northsouthInd == 0) {
            if (slit_edges != NULL ) {
                sinfo_new_destroy_2Dfloatarray(&slit_edges, cfg->nslits);
            }
        }
        else {
            if (distances != NULL ) {
                sinfo_new_destroy_array(&distances);
            }
        }
    }

    sinfo_free_float(&correct_dist);
    sinfo_free_image(&res_flat);
    sinfo_free_image(&res_sky);
    sinfo_free_image(&res_wim);
    sinfo_free_image(&calim);
    sinfo_free_image(&halospec);
    sinfo_free_image(&sky_im);
    sinfo_free_image(&res_obj);
    sinfo_free_image(&flat_im);
    sinfo_free_image(&wavemapim);
    sinfo_free_image(&wim);
    sinfo_free_image(&im);
    sinfo_objnod_free(&cfg);
    sinfo_free_frameset(&stk);

    return -1;

}

static void
sinfo_atm_correction(cpl_imagelist** ppCube, cpl_frameset* sof,
                     const char* polyshiftname, double dis_cube,
                     double centralLambda_cube, int centralpix_cube)
{
    cpl_polynomial* poly = NULL;
    cpl_frame* first_frame = NULL;
    const char* ref_file = NULL;
    cpl_propertylist *plist_cube = NULL;
    cpl_propertylist* ppolylist = NULL;
    cpl_imagelist* retcube = NULL;

    /* we use the pointer outcube as a handle to  *ppCube
 (don't initialize to NULL!)*/
    cpl_imagelist* outcube = *ppCube;
    /* Get the reference file  */
    first_frame = cpl_frameset_get_first(sof);
    ref_file = cpl_frame_get_filename(first_frame);
    if (ref_file && strlen(ref_file)) {
        /* Get FITS header from reference file */
        sinfo_msg_warning("adjusting atmospheric correction ref_file[%s]", ref_file);
        plist_cube = cpl_propertylist_load(ref_file, 0);
        if (plist_cube) {
            // check the OPTI1.NAME
            ppolylist = cpl_propertylist_load(polyshiftname, 0);
            if (ppolylist) {
                double pixelscale = sinfo_pfits_get_pixscale(plist_cube);
                double poly_pixelscale = sinfo_pfits_get_pixscale(ppolylist);
                if (fabs(poly_pixelscale - pixelscale) < 1E-8) {
                    poly = sinfo_atmo_load_polynom(polyshiftname);
                    if (!poly) {
                        sinfo_msg_warning("Cannot load polynom from [%s]",
                                        polyshiftname);
                    }
                    else {
                        sinfo_msg_warning("polynom from [%s] is loaded", polyshiftname);
                    }
                }
                else {
                    sinfo_msg_warning("pixelscale for the polynomial fit "
                                    "is different: provided[%f] expected[%f]",
                                    poly_pixelscale, pixelscale);
                }
                sinfo_free_propertylist(&ppolylist);
            }
            if (!poly) {
                sinfo_msg_warning("Pixel shift due atmospheric refraction"
                                " would not be applied");
            }
        }
        else {
            sinfo_msg_warning("cannot load propertylist for the frame");
        }
        if (poly) {
            double airmass = ((cpl_propertylist_get_double(plist_cube,
                            "ESO TEL AIRM START")
                            + cpl_propertylist_get_double(plist_cube,
                                            "ESO TEL AIRM END")) / 2);
            double angle = ((cpl_propertylist_get_double(plist_cube,
                            "ESO ADA ABSROT START")
                            + cpl_propertylist_get_double(plist_cube,
                                            "ESO ADA ABSROT END")) / 2) * PI_NUMB / 180;
            sinfo_msg("dis_cube[%f] centralLambda_cube[%f] centralpix_cube[%d]",
                      dis_cube, centralLambda_cube, centralpix_cube);
            retcube = sinfo_atmo_apply_cube_polynomial_shift(poly, outcube,
                            centralLambda_cube, airmass, angle, dis_cube,
                            centralpix_cube);
            sinfo_free_polynomial(&poly);
            if (retcube) {
                sinfo_free_imagelist(&outcube);
                *ppCube = retcube;
            }
        }
        sinfo_free_propertylist(&plist_cube);
    }

    return;
}

/* Temporally commented out as not yet used
static cpl_image*
sinfo_flux_corr(const cpl_image* inp, const cpl_image* wav, const double dis)
{

    cpl_image* out = NULL;
    cpl_image* dif = NULL;
    const float* pi = NULL;
    const float* pw = NULL;
    float* po = NULL;
    float* pd = NULL;

    int i = 0;
    int j = 0;
    int nx = 0;
    int ny = 0;
    int stat = 0;
    nx = cpl_image_get_size_x(inp);
    ny = cpl_image_get_size_y(inp);

    out = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
    dif = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
    pi = cpl_image_get_data_const(inp);
    pw = cpl_image_get_data_const(wav);
    po = cpl_image_get_data(out);
    pd = cpl_image_get_data(dif);

    sinfo_msg("dif=%10.8f",
              2. * dis
              / (cpl_image_get(wav, 500, 501, &stat)
                              - cpl_image_get(wav, 500,
                                              499, &stat)));

    sinfo_msg("dif=%10.8f",
              2. * dis
              / (cpl_image_get(wav, 500, 101, &stat)
                              - cpl_image_get(wav, 500,
                                              99, &stat)));

    sinfo_msg("dif=%10.8f",
              2. * dis
              / (cpl_image_get(wav, 500, 1001, &stat)
                              - cpl_image_get(wav, 500,
                                              999, &stat)));

    for (i = 0; i < nx; i++) {
        for (j = 1; j < ny - 1; j++) {
            if (pi[nx * j + i] != ZERO || pw[nx * j + i] != ZERO) {
                po[nx * j + i] = pi[nx * j + i] * dis
                                / ((pw[nx * (j + 1) + i] - pw[nx * (j - 1) + i])
                                                * 0.5);
                pd[nx * j + i] = dis
                                / ((pw[nx * (j + 1) + i] - pw[nx * (j - 1) + i])
                                                * 0.5);
            }
            else {
                po[nx * j + i] = ZERO;
                pd[nx * j + i] = ZERO;
            }
        }

        if (pi[i] != ZERO || pw[i] != ZERO) {
            po[i] = pi[i] * dis / (pw[nx + i] - pw[i]);
            pd[i] = dis / (pw[nx + i] - pw[i]);
        }
        else {
            po[i] = ZERO;
            pd[i] = ZERO;
        }

        if (pi[nx * (ny - 1) + i] != ZERO || pw[nx * (ny - 1) + i] != ZERO) {
            po[nx * (ny - 1) + i] = pi[nx * (ny - 1) + i] * dis
                            / (pw[nx * (ny - 1) + i] - pw[nx * (ny - 2) + i]);
            pd[nx * (ny - 1) + i] = dis
                            / (pw[nx * (ny - 1) + i] - pw[nx * (ny - 2) + i]);
        }
        else {
            po[nx * (ny - 1) + i] = ZERO;
            pd[nx * (ny - 1) + i] = ZERO;
        }

    }
    //cpl_image_save(dif,"diff.fits", CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);

    sinfo_free_image(&dif);

    return out;

}
*/
/**@}*/
