/*
 * 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_prepare_stacked_frames.c
   Author       :    A. Modigliani
   Created on   :    Sep 17, 2003
   Description  :

  this handles stacks of input frames, that means it takes a clean mean,
  subtracts the off- from the on-frames, flatfields, corrects for static bad
  pixels, corrects for a linear tilt of the spectra if necessary, and finally,
  interleaves dithered exposures or convolves a single exposure with a
  Gaussian, respectively.

 ---------------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

/*----------------------------------------------------------------------------
                                Includes
 ---------------------------------------------------------------------------*/
#include "sinfo_new_prepare_stacked_frames.h"
#include "sinfo_stack_ini_by_cpl.h"
#include "sinfo_coltilt.h"
#include "sinfo_image_ops.h"
#include "sinfo_merge.h"
#include "sinfo_utilities.h"
#include "sinfo_wave_calibration.h"
#include "sinfo_new_bezier.h"
#include "sinfo_shift_images.h"
#include "sinfo_product_config.h"

#include "sinfo_pro_save.h"
#include "sinfo_globals.h"
#include "sinfo_utilities.h"
#include "sinfo_dfs.h"
#include "sinfo_raw_types.h"
#include "sinfo_wcal_functions.h"
#include "sinfo_new_bezier.h"

#include "sinfo_hidden.h"
#include "sinfo_pro_types.h"
#include "sinfo_functions.h"
#include "sinfo_utils_wrappers.h"
#include "sinfo_error.h"

/*----------------------------------------------------------------------------
                                Defines
 ---------------------------------------------------------------------------*/
/**@{*/
/**
 * @addtogroup sinfo_rec_jitter Frame stacking
 *
 * TBD
 */



/*----------------------------------------------------------------------------
                             Function Definitions
 ---------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
   Function     :       sinfo_new_prepare_stacked_frames()
   In           :       ini_file: file name of according .ini file
   Out          :       integer (0 if it worked, -1 if it doesn't)
   Job          :
  this handles stacks of input frames, that means it takes a clean mean,
  subtracts the off- from the on-frames, flatfields, corrects for static bad
  pixels, corrects for a linear tilt of the spectra if necessary, and finally,
  interleaves dithered exposures or convolves a single exposure with a
  Gaussian, respectively.

 ---------------------------------------------------------------------------*/
static int
new_get_names(const char* pcatg, const int ind, stack_config_n ** cfg);

static int
new_get_names(const char* pcatg, const int ind, stack_config_n **  cfg){

    if (strcmp(pcatg,PRO_FIBRE_NS_STACKED_OFF) == 0) {
        strcpy((*cfg)->outName,DISTORTION_STACK_OFF_OUT_FILENAME);
    }
    if (strcmp(pcatg,PRO_FIBRE_NS_STACKED_ON)  == 0) {
        strcpy((*cfg)->outName,"out_ns_stack_on.fits");
    }
    if (strcmp(pcatg,PRO_FIBRE_NS_STACKED)     == 0) {
        strcpy((*cfg)->outName,"out_ns_stack.fits");
    }
    if (strcmp(pcatg,PRO_WAVE_LAMP_STACKED)    == 0) {
        strcpy((*cfg)->outName,"out_wcal_stack.fits");
    }
    if (strcmp(pcatg,PRO_FIBRE_NS_STACKED_DIST)== 0) {
        strcpy((*cfg)->outName,"out_ns_stack_warp.fits");
    }
    if (strcmp(pcatg,PRO_WAVE_SLITPOS_STACKED) == 0) {
        strcpy((*cfg)->outName,"out_slit_pos_stack.fits");
    }

    if (strcmp(pcatg,PRO_PSF_CALIBRATOR_STACKED)== 0) {
        snprintf((*cfg)->outName,MAX_NAME_SIZE-1,"%s%d%s","out_stack",ind,".fits");
    }
    if (strcmp(pcatg,PRO_SKY_PSF_CALIBRATOR_STACKED)== 0) {
        strcpy((*cfg)->outName,STACKED_OUT_FILENAME);
    }
    if (strcmp(pcatg,PRO_STD_NODDING_STACKED) == 0) {
        snprintf((*cfg)->outName,MAX_NAME_SIZE-1,"%s%d%s","out_stack",ind,".fits");
    }
    /* only 1 frame
  if (strcmp(pcatg,PRO_STD_NODDING_STACKED) == 0) {
    strcpy((*cfg)->outName,STACKED_OUT_FILENAME);
  }
     */

    if (strcmp(pcatg,PRO_SKY_NODDING_STACKED) == 0) {
        strcpy((*cfg)->outName,STACKED_OUT_FILENAME); /*STD*/
    }
    if (strcmp(pcatg,PRO_OBJECT_NODDING_STACKED) == 0) {
        snprintf((*cfg)->outName,MAX_NAME_SIZE-1,"%s%d%s","out_stack",ind,".fits");
    }
    if (strcmp(pcatg,PRO_PUPIL_LAMP_STACKED) == 0) {
        snprintf((*cfg)->outName,MAX_NAME_SIZE-1,"%s%d%s","out_stack",ind,".fits");
    }
    if (strcmp(pcatg,PRO_STACKED) == 0) {
        snprintf((*cfg)->outName,MAX_NAME_SIZE-1,"%s%d%s","out_stack",ind,".fits");
    }

    snprintf((*cfg)->sky_name,MAX_NAME_SIZE-1,"%s%d%s","out_sky",ind,".fits");

    return 0;

}

static cpl_error_code
sinfo_subtract_raw_sky(int nskydith, stack_config_n* cfg,
                       cpl_image** im_obj, cpl_image** im_sky,
                       cpl_image** im_dither, cpl_image* im_dither_sky)
{
    /*
     #---------------------------------------------------------
     # Subtract the resulting off-frame (sky) from the on-frame
     #-------------------------------------------------------
     # finally, subtract off from on frames and store the result
     # in the object cube
     */

    /* subtract raw sky */
    if (cfg->contains_sky == 1) {
        sinfo_msg("Subtract the off-frame (sky) from the on-frame");
        cpl_image* im_obj_sub = cpl_image_duplicate(*im_obj);
        cpl_image_subtract(im_obj_sub, *im_sky);
        sinfo_free_image(im_obj);
        if (((cfg->contains_dither == 1) && (nskydith > 0))
                        || cfg->contains_dither == 0) {
            sinfo_free_image(im_sky);
            *im_obj = cpl_image_duplicate(im_obj_sub);
        }
        sinfo_free_image(&im_obj_sub);
    }

    if (cfg->contains_dither == 1 && nskydith > 0) {

        cpl_image_subtract(*im_dither, im_dither_sky);

    }
    else if (cfg->contains_dither == 1 && nskydith == 0
                    && cfg->contains_sky == 1) {

        cpl_image_subtract(*im_dither, *im_sky);

    }

    return cpl_error_get_code();
}

static cpl_error_code
sinfo_flat_field(int mflat_norm_smooth, int smooth_rad, int pdensity,
                 const int frm_ind, const char* plugin_id, cpl_image** flat1,
                 stack_config_n* cfg, cpl_image** flat_smooth,
                 cpl_image** im_obj_flat, cpl_image** im_obj,
                 cpl_frameset* raw, cpl_frameset* sof,
                 cpl_parameterlist* config, cpl_image** flat2,
                 cpl_image** im_dither)
{
    /* do flat field */

    sinfo_msg("Flatfielding");
    *flat1 = cpl_image_load(cfg->flatfield1, CPL_TYPE_FLOAT, 0, 0);
    if (mflat_norm_smooth) {
        //We normalize the flat by a smoothed flat
        *flat_smooth = sinfo_image_smooth_median_y(*flat1, smooth_rad);
        cpl_image_divide(*flat1, *flat_smooth);
        sinfo_free_image(flat_smooth);
    }

    *im_obj_flat = sinfo_new_div_images_robust(*im_obj, *flat1);

    /* AMO ** */
    if (pdensity > 1) {
        if (frm_ind == 0) {
            if (cfg->warpfixInd == 1) {
                sinfo_msg("Correct FF for distortions");
                /* AMO check */
                cpl_image* flat1_dist = sinfo_new_image_warp_fits(*flat1,
                                                cfg->kernel, cfg->polyFile);
                sinfo_pro_save_ima(flat1_dist,raw,sof,
                                   STACK_MFLAT_DIST_OUT_FILENAME,
                                   PRO_STACK_MFLAT_DIST,NULL,plugin_id,config);
                sinfo_free_image(&flat1_dist);
            }
        }
    }

    sinfo_free_image(flat1);

    sinfo_free_image(im_obj);
    *im_obj = cpl_image_duplicate(*im_obj_flat);
    sinfo_free_image(im_obj_flat);
    if (pdensity > 1) {
        if (cfg->contains_dither == 1) {
            *flat2 = cpl_image_load(cfg->flatfield2, CPL_TYPE_FLOAT, 0, 0);

            if (mflat_norm_smooth) {

                //We normalize the flat by a smoothed flat
                *flat_smooth = sinfo_image_smooth_median_y(*flat2,
                                                smooth_rad);
                cpl_image_divide(*flat2, *flat_smooth);
                sinfo_free_image(flat_smooth);

            }
            cpl_image* im_dither_flat = sinfo_new_div_images_robust(*im_dither,
                            *flat2);

            if (frm_ind == 0) {
                if (cfg->warpfixInd == 1) {

                    sinfo_msg("Correct FF for distortions");
                    cpl_image* flat2_dist = sinfo_new_image_warp_fits(*flat2,
                                    cfg->kernel,cfg->polyFile);

                    sinfo_pro_save_ima(flat2_dist,raw,sof,
                                       STACK_MFLAT_DITHER_DIST_OUT_FILENAME,
                                       PRO_STACK_MFLAT_DITHER_DIST, NULL,
                                       plugin_id,config);
                    sinfo_free_image(&flat2_dist);
                }
            }
            sinfo_free_image(flat2);
            sinfo_free_image(im_dither);
            *im_dither = cpl_image_duplicate(im_dither_flat);
        }
    }

    return cpl_error_get_code();
}

static cpl_error_code
sinfo_mask_bad_pixels(float val_x, float val_y, cpl_image* mask_im,
                      stack_config_n* cfg, cpl_image** im_obj,
                      cpl_image** im_dither)
{
    sinfo_msg("Static bad pixel correction");

    cpl_image* int_im=NULL;
    cpl_image* int_im_dith=NULL;
    float** slit_edges=NULL;
    char file_name[MAX_NAME_SIZE];
    int status = 0;

    mask_im = cpl_image_load(cfg->mask, CPL_TYPE_FLOAT, 0, 0);
    sinfo_new_change_mask(mask_im, *im_obj);
    if (cfg->indind == 0) {
        /* open the ASCII list of the slitlet positions */
        /*READ TFITS TABLE*/
        strcpy(file_name, cfg->slitposList);
        cpl_table* tbl_slitpos = cpl_table_load(file_name, 1, 0);
        if (cpl_table_has_column(tbl_slitpos, "pos1") != 1) {
            sinfo_msg_error("Column 'pos1' not found in %s table %s",
                            PRO_SLIT_POS, file_name);
            return CPL_ERROR_ILLEGAL_INPUT;
        }
        if (cpl_table_has_column(tbl_slitpos, "pos2") != 1) {
            sinfo_msg_error("Column 'pos2' not found in %s table %s",
                            PRO_SLIT_POS, file_name);
            return CPL_ERROR_ILLEGAL_INPUT;
        }

        int n = cpl_table_get_nrow(tbl_slitpos);
        slit_edges = sinfo_new_2Dfloatarray(n, 2);
        for (int i = 0; i < n; i++) {
            val_x = cpl_table_get_double(tbl_slitpos, "pos1", i, &status);
            val_y = cpl_table_get_double(tbl_slitpos, "pos2", i, &status);
            sinfo_new_array2D_set_value(slit_edges, val_x, i, 0);
            sinfo_new_array2D_set_value(slit_edges, val_y, i, 1);
        }

        sinfo_free_table(&tbl_slitpos);
        int_im = sinfo_interpol_source_image(*im_obj, mask_im,
                                        cfg->maxRad, slit_edges);

        sinfo_free_image(im_obj);
        *im_obj = cpl_image_duplicate(int_im);
        sinfo_free_image(&int_im);

        if (cfg->contains_dither == 1) {
            int_im_dith = sinfo_interpol_source_image(*im_dither,
                                            mask_im, cfg->maxRad, slit_edges);

            sinfo_free_image(im_dither);
            *im_dither = cpl_image_duplicate(int_im_dith);
            sinfo_free_image(&int_im_dith);

        }
        sinfo_new_destroy_2Dfloatarray(&slit_edges, 32);
    }
    else {
        int_im = sinfo_new_mult_image_by_mask(*im_obj, mask_im);

        sinfo_free_image(im_obj);
        *im_obj = cpl_image_duplicate(int_im);
        sinfo_free_image(&int_im);

        if (cfg->contains_dither == 1) {
           int_im_dith = sinfo_new_mult_image_by_mask(*im_dither, mask_im);

            sinfo_free_image(im_dither);
            *im_dither = cpl_image_duplicate(int_im_dith);
            sinfo_free_image(&int_im_dith);
        }
    }
    sinfo_free_image(&mask_im);
    return cpl_error_get_code();

}

static cpl_error_code
sinfo_correct_bad_pixels_bezier(int cnt,stack_config_n* cfg, cpl_image** im_obj,
                                char* name, cpl_image** im_dither)
{
    sinfo_msg("Static bad pixel correction BEZIER");
    char file_name[MAX_NAME_SIZE];

    cpl_image* mask_im = cpl_image_load(cfg->mask, CPL_TYPE_FLOAT, 0, 0);
    sinfo_new_change_mask(mask_im, *im_obj);

    /* #open the FITS table of the slitlet positions-*/
    strcpy(file_name, cfg->slitposList);
    cpl_table* tbl_slitpos = cpl_table_load(file_name, 1, 0);
    int n = cpl_table_get_nrow(tbl_slitpos);
    float** slit_edges = sinfo_new_2Dfloatarray(n, 2);
    int status = 0;
    int i=0;
    for (i = 0; i < n; i++) {
        float val_x = cpl_table_get_double(tbl_slitpos, "pos1", i, &status);
        float val_y = cpl_table_get_double(tbl_slitpos, "pos2", i, &status);
        sinfo_new_array2D_set_value(slit_edges, val_x, i, 0);
        sinfo_new_array2D_set_value(slit_edges, val_y, i, 1);
    }
    sinfo_free_table(&tbl_slitpos);
    strcpy(file_name, cfg->indexlist);
    cpl_table* tbl_index = cpl_table_load(file_name, 1, 0);
    n = cpl_table_get_nrow(tbl_index);
    char** in_nam = (char** ) cpl_calloc(n, sizeof(char*));
    for (i = 0; i < n; i++) {
        strcpy(*in_nam[i], cpl_table_get_string(tbl_index, "name", i));
    }
    sinfo_free_table(&tbl_index);
    cpl_imagelist* iCube = NULL;
    cpl_imagelist* jCube = NULL;
    cpl_image* X =NULL;
    cpl_image* Y =NULL;
    cpl_image* Z =NULL;
    cpl_image* hX =NULL;
    for (i = 0; i < cnt; i++) {
        if (strcmp("ICube.fits", name) != 0) {
            iCube = cpl_imagelist_load("ICube.fits", CPL_TYPE_FLOAT, 0);
        }
        else if (strcmp("JCube.fits", name) != 0) {
            jCube = cpl_imagelist_load("JCube.fits", CPL_TYPE_FLOAT, 0);
        }
        else if (strcmp("X.fits", name) != 0) {
            X = cpl_image_load("X.fits", CPL_TYPE_FLOAT, 0, 0);
        }
        else if (strcmp("Y.fits", name) != 0) {
            Y = cpl_image_load("Y.fits", CPL_TYPE_FLOAT, 0, 0);
        }
        else if (strcmp("Z.fits", name) != 0) {
            Z = cpl_image_load("Z.fits", CPL_TYPE_FLOAT, 0, 0);
        }
        else if (strcmp("cX.fits", name) != 0) {
            hX = cpl_image_load("cX.fits", CPL_TYPE_FLOAT, 0, 0);
        }
        else {
            sinfo_msg_error(
                            "wrong name in index list or needed file not there!");
            return CPL_ERROR_ILLEGAL_INPUT;
        }
    }
    new_Lookup* lookup = sinfo_new_lookup();
    lookup->id = iCube;
    lookup->jd = jCube;
    lookup->X = X;
    lookup->Y = Y;
    lookup->Z = Z;
    lookup->hX = hX;
    *im_obj = sinfo_new_c_bezier_interpolate_image(*im_obj,
                                    mask_im, lookup, cfg->maxRad, cfg->maxRad,
                                    cfg->maxRad, 2, slit_edges);
    *im_obj = sinfo_new_c_bezier_find_bad(*im_obj, mask_im,
                                    cfg->maxRad, cfg->maxRad, cfg->maxRad, 0,
                                    cpl_image_get_size_x(*im_obj), 0,
                                    cpl_image_get_size_y(*im_obj),
                                    cfg->sigmaFactor);
    if (cfg->contains_dither == 1) {
        *im_dither = sinfo_new_c_bezier_interpolate_image(
                                        *im_dither, mask_im, lookup, cfg->maxRad,
                                        cfg->maxRad, cfg->maxRad, 2,
                                        slit_edges);

        *im_dither = sinfo_new_c_bezier_find_bad(*im_dither,
                                        mask_im, cfg->maxRad, cfg->maxRad,
                                        cfg->maxRad, 0,
                                        cpl_image_get_size_x(*im_obj), 0,
                                        cpl_image_get_size_y(*im_obj),
                                        cfg->sigmaFactor);

    }
    sinfo_new_destroy_2Dfloatarray(&slit_edges, 32);
    sinfo_free_image(&mask_im);
    sinfo_free_imagelist(&iCube);
    sinfo_free_imagelist(&jCube);
    sinfo_free_image(&lookup->X);
    sinfo_free_image(&lookup->X);
    sinfo_free_image(&lookup->Y);
    sinfo_free_image(&lookup->hX);
    sinfo_new_destroy_lookup(lookup);
    return cpl_error_get_code();

}

static cpl_error_code
sinfo_correct_bad_pixels_bezier3(int cnt,stack_config_n* cfg,
                                 cpl_image** im_obj, cpl_image** im_dither)
{
    char file_name[MAX_NAME_SIZE];

    cpl_image* mask_im = cpl_image_load(cfg->mask, CPL_TYPE_FLOAT, 0, 0);
    /* #open the ASCII list of the slitlet positions-- */
    strcpy(file_name, cfg->slitposList);
    cpl_table* tbl_slitpos = cpl_table_load(file_name, 1, 0);
    if (cpl_table_has_column(tbl_slitpos, "pos1") != 1) {
        sinfo_msg_error("Column 'pos1' not found in %s table %s", PRO_SLIT_POS,
                        file_name);
        return CPL_ERROR_ILLEGAL_INPUT;

    }
    if (cpl_table_has_column(tbl_slitpos, "pos2") != 1) {
        sinfo_msg_error("Column 'pos2' not found in %s table %s", PRO_SLIT_POS,
                        file_name);
        return CPL_ERROR_ILLEGAL_INPUT;

    }
    int n = cpl_table_get_nrow(tbl_slitpos);
    float** slit_edges  = sinfo_new_2Dfloatarray(n, 2);
     int status = 0;
     int i;
    for (i = 0; i < n; i++) {
        float val_x = cpl_table_get_double(tbl_slitpos, "pos1", i, &status);
        float val_y = cpl_table_get_double(tbl_slitpos, "pos2", i, &status);
        sinfo_new_array2D_set_value(slit_edges, val_x, i, 0);
        sinfo_new_array2D_set_value(slit_edges, val_y, i, 1);
    }
    sinfo_free_table(&tbl_slitpos);
    strcpy(file_name, cfg->indexlist);
    cpl_table* tbl_index = cpl_table_load(file_name, 1, 0);
    n = cpl_table_get_nrow(tbl_index);
    char** in_nam = (char** ) cpl_calloc(n, sizeof(char*));
    for (i = 0; i < n; i++) {
        strcpy(in_nam[i], cpl_table_get_string(tbl_index, "name", i));
    }
    sinfo_free_table(&tbl_index);
    cpl_imagelist* iCube = NULL;
    cpl_imagelist* jCube = NULL;
    cpl_image* X = NULL;
    cpl_image* Y = NULL;
    cpl_image* Z = NULL;
    cpl_image* hX = NULL;

    for (i = 0; i < cnt; i++) {
        if (strcmp("ICube.fits", in_nam[i]) != 0) {
            iCube = cpl_imagelist_load("ICube.fits",CPL_TYPE_FLOAT, 0);
        }
        else if (strcmp("JCube.fits", in_nam[i]) != 0) {
            jCube = cpl_imagelist_load("JCube.fits", CPL_TYPE_FLOAT, 0);
        }
        else if (strcmp("X.fits", in_nam[i]) != 0) {
            X = cpl_image_load("X.fits", CPL_TYPE_FLOAT, 0, 0);
        }
        else if (strcmp("Y.fits", in_nam[i]) != 0) {
            Y = cpl_image_load("Y.fits", CPL_TYPE_FLOAT, 0, 0);
        }
        else if (strcmp("Z.fits", in_nam[i]) != 0) {
            Z = cpl_image_load("Z.fits", CPL_TYPE_FLOAT, 0, 0);
        }
        else if (strcmp("cX.fits", in_nam[i]) != 0) {
            hX = cpl_image_load("cX.fits", CPL_TYPE_FLOAT, 0, 0);
        }
        else {
            sinfo_msg_error(
                            "wrong name in index list or needed file not there!");
            return CPL_ERROR_ILLEGAL_INPUT;

        }
    }
    new_Lookup* lookup = sinfo_new_lookup();
    lookup->id = iCube;
    lookup->jd = jCube;
    lookup->X = X;
    lookup->Y = Y;
    lookup->Z = Z;
    lookup->hX = hX;
    *im_obj = sinfo_new_c_bezier_interpolate_image(*im_obj,
                                    mask_im, lookup, cfg->maxRad, cfg->maxRad,
                                    cfg->maxRad, 2, slit_edges);
    if (cfg->contains_dither == 1) {
        *im_dither = sinfo_new_c_bezier_interpolate_image(
                                        *im_dither, mask_im, lookup, cfg->maxRad,
                                        cfg->maxRad, cfg->maxRad, 2,
                                        slit_edges);

    }
    sinfo_new_destroy_2Dfloatarray(&slit_edges, 32);
    sinfo_free_image(&mask_im);
    sinfo_free_imagelist(&iCube);
    sinfo_free_imagelist(&jCube);
    sinfo_free_image(&lookup->X);
    sinfo_free_image(&lookup->Y);
    sinfo_free_image(&lookup->Z);
    sinfo_free_image(&lookup->hX);
    sinfo_new_destroy_lookup(lookup);
    return cpl_error_get_code();

}

static cpl_error_code
sinfo_interleave_frames(cpl_image* im_obj, cpl_image** im_dither, int noRows,
                        cpl_image** im9)
{

    sinfo_msg("Merge (interleave) frames");
    cpl_image* im3 = cpl_image_new(cpl_image_get_size_x(im_obj),
                    cpl_image_get_size_y(im_obj),
                    CPL_TYPE_FLOAT);

    cpl_image* im4 = sinfo_new_remove_general_offset(im_obj, *im_dither,
                    im3, noRows);

    cpl_image* im5 = sinfo_new_remove_regional_tilt(im_obj, im4, im3);
    cpl_image* im6 = sinfo_new_remove_column_offset(im_obj, im5, im3);
    cpl_image* im7 = sinfo_new_remove_residual_tilt(im6, im3);
    cpl_image* im8 = sinfo_new_remove_residual_offset(im7, im3);
    * im9 = sinfo_sinfo_merge_images(im_obj, im8, im3);

    sinfo_free_image(&im3);
    sinfo_free_image(&im4);
    sinfo_free_image(&im5);
    sinfo_free_image(&im6);
    sinfo_free_image(&im7);
    sinfo_free_image(&im8);


    return cpl_error_get_code();

}

static cpl_table*
sinfo_compute_qc(qc_wcal* qc, cpl_image* im_obj)
{
    sinfo_msg("Add QC LOG");
    /* add QC-LOG */
    /* sinfo_det_ncounts(raw, cfg->qc_thresh_max); */
    cpl_table* qclog_tbl = sinfo_qclog_init();
    sinfo_qclog_add_double(qclog_tbl, "QC FRMON MEANFLUX",
                                    qc->avg_on, "Average of flux", "%g");
    /*    ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC FRMON MEANFLUX",
     qc->avg_on,"Average of flux","%g"));*/
    sinfo_qclog_add_double(qclog_tbl, "QC FRMOFF MEANFLUX",
                                    qc->avg_of, "Average of flux", "%g");
    sinfo_qclog_add_double(qclog_tbl, "QC FRMDIF MEANFLUX",
                                    qc->avg_di, "Average of flux", "%g");
    sinfo_qclog_add_double(qclog_tbl, "QC FRMON MAXFLUX",
                                    qc->max_on, "Max of flux", "%g");
    sinfo_qclog_add_double(qclog_tbl, "QC FRMOFF MAXFLUX",
                                    qc->max_of, "Max of flux", "%g");
    sinfo_qclog_add_double(qclog_tbl, "QC FRMDIF MAXFLUX",
                                    qc->max_di, "Max of flux", "%g");
    sinfo_qclog_add_int(qclog_tbl, "QC FRMON NPIXSAT", qc->nsat,
                                    "Number of saturated pixels", "%d");
    update_bad_pixel_map(im_obj);
    sinfo_qclog_add_double(qclog_tbl, "QC FRMDIF MEANSTD",
                                    cpl_image_get_mean(im_obj),
                                    "mean of the image", "%13.6f");
    sinfo_qclog_add_double(qclog_tbl, "QC FRMDIF STDEV",
                                    cpl_image_get_stdev(im_obj),
                                    "standard deviation of the image",
                                    "%13.6f");


    return qclog_tbl;
}

static cpl_error_code
sinfo_special_case(int i, const char* frm_pro_ctg, const char* plugin_id,
                   int mflat_norm_smooth, int smooth_rad,
                   cpl_frameset* raw, const int frm_ind, cpl_frameset* sof,
                   cpl_parameterlist* config, stack_config_n* cfg)
{

    char file_name[MAX_NAME_SIZE];
    cpl_frame* sky_frame = cpl_frameset_get_frame(raw,i);
    char* sky_name = (char* ) cpl_frame_get_filename(sky_frame);
    /* check_nomsg(sky_tag   = (char*) cpl_frame_get_tag(sky_frame)); */
    if ((strstr(frm_pro_ctg, "OBJECT") != NULL)
                    || (strstr(frm_pro_ctg, "PSF") != NULL)
                    || (strstr(frm_pro_ctg, "STD") != NULL)) {
        cpl_image* sky_img = cpl_image_load(sky_name, CPL_TYPE_FLOAT, 0, 0);
        snprintf(sky_name, MAX_NAME_SIZE - 1, "%s%2.2d%s", "out_sky", frm_ind,
                        ".fits");
        sinfo_pro_save_ima(sky_img, raw, sof, sky_name, PRO_SKY_STACKED_DUMMY,
                           NULL, plugin_id, config);

        sinfo_free_image(&sky_img);
        if (cfg->flatInd == 1) {
            sinfo_msg("Sky Flatfielding");
            cpl_image* flat1 = cpl_image_load(cfg->flatfield1, CPL_TYPE_FLOAT, 0, 0);

            if (mflat_norm_smooth != 0) {
                cpl_image* flat_smooth = NULL;
                if (mflat_norm_smooth == 1) {

                    int sy = cpl_image_get_size_y(flat1);

                    flat_smooth = sinfo_image_smooth_fft(flat1,
                                                    sy / smooth_rad);
                }
                else if (mflat_norm_smooth == 2) {
                    flat_smooth = sinfo_image_smooth_median_y(
                                                    flat1, smooth_rad);
                }

                cpl_image_divide(flat1, flat_smooth);
                sinfo_free_image(&flat_smooth);

            }

            cpl_image* simg = cpl_image_load(sky_name, CPL_TYPE_FLOAT, 0, 0);

            cpl_image* sky_img_flat = sinfo_new_div_images_robust(simg, flat1);
            sinfo_free_image(&simg);
            sinfo_free_image(&flat1);

            /* if (frm_ind == 0) { */
            if (cfg->warpfixInd == 1) {
                sinfo_msg("Correct sky for distortions");
                snprintf(file_name, MAX_NAME_SIZE - 1, "%s%d%s",
                STACK_SKY_DIST_OUT_FILENAME, frm_ind, ".fits");
                cpl_image* sky_dist = sinfo_new_image_warp_fits(sky_img_flat,
                                cfg->kernel, cfg->polyFile);

                sinfo_pro_save_ima(sky_dist,raw,sof, file_name,
                                   PRO_STACK_SKY_DIST, NULL, plugin_id, config);

                sinfo_free_image(&sky_dist);
            }
            /* } */
            sinfo_free_image(&sky_img_flat);
        } /* end check on flatind */
    }
    return cpl_error_get_code();
}

int sinfo_new_prepare_stacked_frames (const char* plugin_id,
                                      cpl_parameterlist* config,
                                      cpl_frameset* sof,
                                      cpl_frameset* ref_set,
                                      const char* frm_pro_ctg,
                                      const int frm_ind,
                                      fake* fk)
{


    stack_config_n * cfg =NULL;
    cpl_imagelist * list_object=NULL ;
    cpl_imagelist * list_dither_object=NULL;
    cpl_imagelist * list_dither_sky=NULL;
    cpl_imagelist * list_sky=NULL;
    cpl_imagelist * list_dark=NULL;

    cpl_image * ref_im1=NULL ;
    cpl_image * ref_im2=NULL ;
    cpl_image ** im=NULL ;
    cpl_image * im_obj=NULL ;

    cpl_image * im_dark=NULL ;
    cpl_image * im_sky=NULL ;
    cpl_image * im_dither=NULL ;
    cpl_image * im_dither_sky=NULL ;
    cpl_image * im_obj_flat=NULL ;
    cpl_image * int_im_shifted=NULL ;
    cpl_image * int_im_dith_shifted=NULL ;
    cpl_image * im_conv=NULL ;

    cpl_image * mask_im=NULL ;
    cpl_image * flat_smooth=NULL ;
    cpl_image * flat1=NULL ;
    cpl_image * flat2=NULL ;

    cpl_image * sky_img_flat=NULL;
    cpl_image * sky_dist=NULL;

    cpl_image* sky_img=NULL;
    cpl_image* mdark=NULL;

    char* name=NULL;
    int typ=0;
    int pos=0;
    int i = 0;
    int cnt = 0 ;
    float val_x=0;
    float val_y=0;

    float** slit_edges=NULL;

    int nob = 0;
    int nsky = 0;
    int nobjdith = 0;
    int nskydith = 0;
    int nda = 0;
    char name_list[MAX_NAME_SIZE];
    char fake_sky_name[MAX_NAME_SIZE];
    int no=0;
    float lo_cut=0;
    float hi_cut=0;

    cpl_imagelist* list_object_tmp=NULL;
    cpl_imagelist* list_dither_object_tmp=NULL;
    cpl_imagelist* list_sky_tmp=NULL;
    cpl_imagelist* list_dither_sky_tmp=NULL;

    cpl_frameset* raw=NULL;

    cpl_table* tbl_index = NULL;
    cpl_table* tbl_slitpos=NULL;
    /* int rhead=0; */

    /* char* sky_tag   = NULL; */
    qc_wcal* qc=sinfo_qc_wcal_new();

    cpl_parameter* p=NULL;
    int pdensity=0;
    int mflat_norm_smooth=FALSE;

    int smooth_rad=16;
    int sub_raw_sky=1;

    /*
       -----------------------------------------------------------------
       1) parse the file names and parameters to the psf_config data
          structure cfg
       -----------------------------------------------------------------
     */


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



    check_nomsg(p=cpl_parameterlist_find(config,
                    "sinfoni.stacked.mflat_norm_smooth"));
    check_nomsg(mflat_norm_smooth=cpl_parameter_get_int(p));



    check_nomsg(p=cpl_parameterlist_find(config,
                    "sinfoni.stacked.mflat_smooth_rad"));
    check_nomsg(smooth_rad=cpl_parameter_get_int(p));

    check_nomsg(p=cpl_parameterlist_find(config,"sinfoni.stacked.sub_raw_sky"));
    check_nomsg(sub_raw_sky=cpl_parameter_get_bool(p));


    check_nomsg(raw=cpl_frameset_new());
    cknull(cfg = sinfo_parse_cpl_input_stack(config,sof,&raw, fk),
           "could not parse cpl input file!") ;

    ck0(sinfo_det_ncounts(raw, cfg->qc_thresh_max,qc),"computing det ncounts");


    if(ref_set != NULL) {
        sinfo_free_frameset(&raw);
        raw=cpl_frameset_duplicate(ref_set);
    }
    /* defines output file name for stack set i */
    ck0_nomsg(new_get_names(frm_pro_ctg, frm_ind, &cfg));

    if (cfg->flatInd == 1){
        if(sinfo_is_fits_file(cfg->flatfield1) != 1) {
            sinfo_msg_error("Input FF file %s is not FITS",cfg->flatfield1);
            goto cleanup;
        }

    }
    if (cfg->maskInd == 1) {
        if(sinfo_is_fits_file(cfg->mask) != 1) {
            sinfo_msg_error("Input mask file %s is not FITS",cfg->mask);
            goto cleanup;
        }
        if(cfg -> indind == 0) {
            if(sinfo_is_fits_file(cfg->slitposList) != 1) {
                sinfo_msg_error("Input slitpos file %s is not FITS",cfg->slitposList);
                goto cleanup;
            }
        }
    }

    /*
   #---------------------------------------------------------
   # Take a clean mean of several images
   # input is 1 or more similar images
   #---------------------------------------------------------
     */

    if (cfg->sfInd == 1){
        if (cfg->contains_dark == 0) {
            sinfo_msg_warning("no sinfo_dark frames given!");
        }
        if (cfg->contains_ref == 0) {
            sinfo_msg_error("no reference frames given!");
            goto cleanup;
        }
    }

    /* allocate memory for lists of object, sky and dithered frames */
    check(list_object=cpl_imagelist_new(),
          "could not allocate memory for object frame");

    if (cfg->contains_dither == 1) {
        check(list_dither_object=cpl_imagelist_new(),
                        "could not allocate memory for dither object frame");
    }

    if (cfg->contains_sky == 1) {
        check(list_sky = cpl_imagelist_new(),
                        "could not allocate memory for off frame list");
    }

    if (cfg->contains_dither == 1 && cfg->nditheroff > 0) {
        check(list_dither_sky = cpl_imagelist_new(),
                        "could not allocate memory for dither frame list");
    }

    if (cfg->contains_dark == 1 && cfg->sfInd == 1) {
        check(list_dark = cpl_imagelist_new(),
                        "could not allocate memory for sinfo_dark frame");
    }

    if (cfg->contains_dither == 0 && cfg->nditheroff > 0) {
        sinfo_msg_error("please use non-dithered off-frames, remove the 2!");
        goto cleanup;
    }

    /* build different image lists for the different cases */
    cknull_nomsg(im=(cpl_image**)cpl_calloc(cfg -> nframes, sizeof(cpl_image*)));

    for (i=0; i< cfg->nframes; i++) {
        name = cfg->framelist[i];
        if(sinfo_is_fits_file(name) != 1) {
            sinfo_msg_error("Input file %s is not FITS",name);
            goto cleanup;
        }
        check_nomsg(im[i] = cpl_image_load( name,CPL_TYPE_FLOAT,0,0));
    }

    /* up to here leak free */
    /* rhead=0; */
    for (i=0; i< cfg->nframes; i++) {
        typ = sinfo_new_intarray_get_value( cfg->frametype, i );
        pos = sinfo_new_intarray_get_value( cfg->frameposition, i );
        cknull(im[i],"could not load image");

        if (pos == 2) {
            if (typ == 1) {
                check_nomsg(cpl_imagelist_set(list_object,
                                cpl_image_duplicate(im[i]),nob));
                nob = nob + 1;
            }
            else if ( typ == 0 ) {
                check_nomsg(cpl_imagelist_set(list_sky,
                                cpl_image_duplicate(im[i]),nsky));
                nsky = nsky + 1;
                if(pdensity > 0) {
                    if(fk->is_fake_sky==1) {
                        snprintf(fake_sky_name,MAX_NAME_SIZE-1,"%s%d%s","out_fake_sky",
                                        frm_ind,".fits");
                        check_nomsg(sky_img=cpl_image_load(fake_sky_name,CPL_TYPE_FLOAT,0,0));
                        ck0(sinfo_pro_save_ima(sky_img,raw,sof,fake_sky_name,
                                        PRO_SKY_DUMMY,NULL,
                                        plugin_id,config),
                            "cannot save sky ima %s", fake_sky_name);

                        sinfo_free_image(&sky_img);
                    }
                }


                if((pdensity == 3) || (pdensity == 1) ||
                                (pdensity == 2 && frm_ind == 0)) {


                    sinfo_special_case(i, frm_pro_ctg, plugin_id,
                                    mflat_norm_smooth, smooth_rad,
                                    raw, frm_ind, sof, config, cfg);
                }
            } else if ( typ == 5 ) {
                if (cfg->sfInd == 1) {
                    check_nomsg(cpl_imagelist_set(list_dark,
                                    cpl_image_duplicate(im[i]),nda));
                    nda = nda + 1;
                } else {
                    sinfo_free_image(&(im[i]));
                }
            } else if ( typ == 4 ) {
                if ( cfg->sfInd == 1) {
                    ref_im1 = im[i];
                } else {
                    sinfo_free_image(&(im[i]));
                }
            }
        } else {
            if (typ == 1) {
                check_nomsg(cpl_imagelist_set(list_dither_object,
                                cpl_image_duplicate(im[i]),nobjdith));
                nobjdith = nobjdith + 1;
            } else if (typ == 0) {
                check_nomsg(cpl_imagelist_set(list_dither_object,
                                cpl_image_duplicate(im[i]),nskydith));
                nskydith = nskydith + 1;
            } else if (typ == 4) {
                if (cfg->sfInd == 1) {
                    ref_im2 = cpl_image_duplicate(im[i]);
                } else {
                    sinfo_free_image(&(im[i]));
                }
            }
        }
    } /* end for loop on i */

    if (nob != cfg->nobj ||
                    cfg->noff != nsky ||
                    nobjdith != cfg->nditherobj ||
                    nskydith != cfg->nditheroff) {
        sinfo_msg_error("something is wrong with the number of the");
        sinfo_msg_error("different types of frames");
        /* free memory */
        goto cleanup;

    }

    if (cfg->sfInd == 1 && nda != cfg->ndark) {
        sinfo_msg_error("something is wrong with the number of sinfo_dark frames");
        goto cleanup;
    }
    sinfo_msg("Create and fill cubes with the different images");

    /* create and fill cubes with the different image lists */
    cknull(list_object,"could not create object data cube!");

    /* shift the images in the cubes-if indicated-in spectral direction
     with respect to the reference image
     */
    if (cfg->sfInd == 1) {

        /*
      first take the mean of the sinfo_dark frames and subtract the result
      from all cubes
         */
        sinfo_msg("Shift cube images in spectral direction with "
                        "respect to reference");

        if (cfg->contains_dark == 1) {
            sinfo_msg("cfg->contains_dark == 1");
            if (cfg->loReject*cfg->ndark < 1. && cfg->hiReject * cfg->ndark < 1.) {
                /*
          im_dark = sinfo_new_average_cube_to_image( list_dark );
                 */
                check(im_dark = cpl_imagelist_collapse_create( list_dark ),
                                "sinfo_averageCubeToImage failed" );
            }
            else {

                check_nomsg(no=cpl_imagelist_get_size(list_dark));
                lo_cut=(floor)( cfg->loReject*no+0.5);
                hi_cut=(floor)( cfg->hiReject*no+0.5);
                check(im_dark=cpl_imagelist_collapse_minmax_create(list_dark,lo_cut,
                                hi_cut),
                      "sinfo_average_with_rejection failed" );

            }
            sinfo_free_imagelist(&list_dark);
            check_nomsg(list_object_tmp = cpl_imagelist_duplicate (list_object));
            check(cpl_imagelist_subtract_image (list_object_tmp, im_dark),
                  "cpl_imagelist_subtract_image failed" );
            /*
       cube_object_tmp = sinfo_subImageFromCube (cube_object, im_dark);
             */
        } else {
            sinfo_msg("cfg->contains_dark == 0");
            check_nomsg(list_object_tmp = cpl_imagelist_duplicate(list_object));
        }
        sinfo_free_imagelist(&list_object);

        cknull(list_object = sinfo_align_cube_to_reference (list_object_tmp,
                        ref_im1,
                        cfg->sfOrder,
                        cfg->sfType),
               "sinfo_align_cube_to_reference failed" );

        sinfo_free_imagelist(&list_object_tmp);
        if (cfg->contains_dither == 1) {
            if (cfg->contains_dark == 1) {
                check_nomsg(list_dither_object_tmp =
                                cpl_imagelist_duplicate(list_dither_object));
                check(cpl_imagelist_subtract_image(list_dither_object_tmp,im_dark),
                      "sinfo_average_with_rejection failed" );

                /*
        list_dither_object_tmp =
              sinfo_new_sub_image_from_cube(list_dither_object,
                                                    im_dark);
                 */

            } else {
                check_nomsg(list_dither_object_tmp=
                                cpl_imagelist_duplicate(list_dither_object));
            }
            sinfo_free_imagelist(&list_dither_object);

            cknull(list_dither_object=
                            sinfo_align_cube_to_reference (list_dither_object_tmp,
                                            ref_im2,
                                            cfg->sfOrder,
                                            cfg->sfType),
                                            "sinfo_align_cube_to_reference failed" );

            sinfo_free_imagelist(&list_dither_object_tmp);
        }
        if (cfg->contains_sky == 1) {
            if (cfg->contains_dark == 1) {
                check_nomsg(list_sky_tmp = cpl_imagelist_duplicate(list_sky));
                check(cpl_imagelist_subtract_image (list_sky_tmp, im_dark),
                      "sinfo_average_with_rejection failed" );
                /*
      cube_sky_tmp = sinfo_subImageFromCube (cube_sky, im_dark);
                 */

            } else {
                check_nomsg(list_sky_tmp = cpl_imagelist_duplicate(list_sky));
            }
            check_nomsg(list_sky_tmp=cpl_imagelist_duplicate(list_sky));

            check(list_sky = sinfo_align_cube_to_reference (list_sky_tmp,
                            ref_im1,
                            cfg->sfOrder,
                            cfg->sfType),
                  "sinfo_alignCubeToReference failed" );

            check_nomsg(cpl_imagelist_delete(list_sky_tmp));
        }
        if (cfg->contains_dither == 1 && cfg->contains_sky == 1) {
            if (cfg->contains_dark == 1) {
                check_nomsg(list_dither_sky_tmp=cpl_imagelist_duplicate(list_dither_sky));
                check(cpl_imagelist_subtract_image(list_dither_sky_tmp,im_dark),
                      "sinfo_average_with_rejection failed" );
                /*
       cube_dither_sky_tmp = sinfo_subImageFromCube (cube_dither_sky, im_dark);
                 */

            } else {
                check_nomsg(list_dither_sky_tmp=cpl_imagelist_duplicate(list_dither_sky));
            }
            sinfo_free_imagelist(&list_dither_sky);

            check(list_dither_sky=sinfo_align_cube_to_reference(list_dither_sky_tmp,
                            ref_im2,
                            cfg->sfOrder,
                            cfg->sfType),
                  "sinfo_alignCubeToReference failed" );

            sinfo_free_imagelist(&list_dither_sky_tmp);
        }
        sinfo_free_image(&ref_im1);
        if (cfg->contains_dither == 1) {
            sinfo_free_image(&ref_im2);
        }
        if (cfg->contains_dark == 1) {
            sinfo_free_image(&im_dark);
        }

    } /* end if over sfInd */

    /* subtracts the master dark from different frames if present */
    if(cfg->mdark_ind==1){
        sinfo_msg("Subtract master dark %s ",cfg->mdark);

        check_nomsg(mdark=cpl_image_load(cfg->mdark,CPL_TYPE_FLOAT,0,0));
        if (list_object !=NULL) {
            cpl_imagelist_subtract_image (list_object, mdark);
        }
        if (list_sky !=NULL) {
            cpl_imagelist_subtract_image (list_sky, mdark);
        }
        sinfo_free_image(&mdark);
    }
    /* take the average with rejection of the different cubes */
    sinfo_msg("Take the average of the different cubes");

    if (cfg->loReject*cfg->nobj < 1. && cfg->hiReject * cfg->nobj < 1.) {
        check(im_obj = cpl_imagelist_collapse_create(list_object),
                        "Average with rejection failed" );
    } else {

        check_nomsg(no=cpl_imagelist_get_size(list_object));
        lo_cut=(floor)( cfg->loReject*no+0.5);
        hi_cut=(floor)( cfg->hiReject*no+0.5);
        check(im_obj=cpl_imagelist_collapse_minmax_create(list_object,
                        lo_cut,hi_cut),"Average with rejection failed" );

    }
    sinfo_free_imagelist(&list_object);

    if (cfg->contains_sky == 1) {
        if (cfg->loReject*nsky < 1. && cfg->hiReject*nsky < 1.) {
            /* here might explode in dither mode */
            cknull(im_sky = cpl_imagelist_collapse_create( list_sky ),
                            "Average with rejection failed");
        } else {

            check_nomsg(no=cpl_imagelist_get_size(list_sky));
            lo_cut=(floor)( cfg->loReject*no+0.5);
            hi_cut=(floor)( cfg->hiReject*no+0.5);
            check(im_sky=cpl_imagelist_collapse_minmax_create(list_sky,lo_cut,hi_cut),
                  "Average with rejection failed");
        }
        sinfo_free_imagelist(&list_sky);
    }

    if (cfg->contains_dither == 1) {
        if (cfg->loReject*nobjdith < 1. && cfg->hiReject*nobjdith < 1.) {
            check(im_dither = cpl_imagelist_collapse_create( list_dither_object ),
                            "Average with rejection failed");
        } else {

            check_nomsg(no=cpl_imagelist_get_size(list_dither_object));
            lo_cut=(floor)( cfg->loReject*no+0.5);
            hi_cut=(floor)( cfg->hiReject*no+0.5);
            check(im_dither=cpl_imagelist_collapse_minmax_create(list_dither_object,
                            lo_cut,hi_cut),
                  "Average with rejection failed");

        }
        sinfo_free_imagelist(&list_dither_object);
    }

    if (cfg->contains_dither == 1 && nskydith > 0) {
        if (cfg->loReject*nskydith < 1. && cfg->hiReject*nskydith < 1.) {
            check(im_dither_sky = cpl_imagelist_collapse_create( list_dither_sky ),
                            "Average with rejection failed");
        } else {

            check_nomsg(no=cpl_imagelist_get_size(list_dither_sky));
            lo_cut=(floor)( cfg->loReject*no+0.5);
            hi_cut=(floor)( cfg->hiReject*no+0.5);
            check(im_dither_sky=cpl_imagelist_collapse_minmax_create(list_dither_sky,
                            lo_cut,hi_cut),
                  "Average with rejection failed");
        }
        sinfo_free_imagelist(&list_dither_sky);
    }

    /*
  #---------------------------------------------------------
  # Subtract the resulting off-frame (sky) from the on-frame
  #-------------------------------------------------------
  # finally, subtract off from on frames and store the result
  # in the object cube
     */
    if (sub_raw_sky == 1) {
        sinfo_subtract_raw_sky(nskydith, cfg, &im_obj, &im_sky,
                               &im_dither, im_dither_sky);
    }
    /*
  #---------------------------------------------------------
  # Flatfielding
  #---------------------------------------------------------
     */

    if (cfg->flatInd == 1) {


        /* do flat field */
        sinfo_flat_field(mflat_norm_smooth, smooth_rad, pdensity,
                        frm_ind, plugin_id, &flat1, cfg, &flat_smooth,
                        &im_obj_flat, &im_obj, raw, sof, config,
                        &flat2, &im_dither);
    }

    /*
  #---------------------------------------------------------
  # static bad pixel correction
  #---------------------------------------------------------
     */

    if (cfg->maskInd == 1) {

        sinfo_mask_bad_pixels(val_x, val_y, mask_im, cfg, &im_obj, &im_dither);

    }

    /*
  #---------------------------------------------------------
  # static bad pixel correction BEZIER
  #---------------------------------------------------------
     */

    if (cfg->maskInd == 2){

        sinfo_correct_bad_pixels_bezier(cnt,cfg, &im_obj, name, &im_dither);
    }

    if (cfg->maskInd == 3) {

        sinfo_correct_bad_pixels_bezier3(cnt, cfg, &im_obj, &im_dither);

    }


    /*
  #---------------------------------------------------------
  # correction of distortions
  #---------------------------------------------------------
     */

    /* here memory leak */
    //sinfo_msg("cfg->warpfixInd=%d",cfg->warpfixInd);
    if (cfg->warpfixInd == 1){
        /*#open ASCII file containing the slope parameter and read it*/
        sinfo_msg("Correct object for distortions");
        cknull(int_im_shifted=sinfo_new_image_warp_fits(im_obj,
                        cfg->kernel,
                        cfg->polyFile),
               "could not carry out sinfo_image_warp_fits" );

        sinfo_free_image(&im_obj);
        im_obj = cpl_image_duplicate(int_im_shifted);
        if (cfg->contains_dither == 1){
            cknull(int_im_dith_shifted=sinfo_new_image_warp_fits(im_dither,
                            cfg->kernel,
                            cfg->polyFile),
                            "could not carry out sinfo_image_warp_fits" );
            sinfo_free_image(&im_dither);
            im_dither = cpl_image_duplicate(int_im_dith_shifted);
        }
    }

    /*
  #---------------------------------------------------------
  # merge (interleave) both resulting frames
  #---------------------------------------------------------
     */
    if (cfg->interInd == 1 && cfg->contains_dither == 1){
        if (pdensity > 1) {
            cpl_image * im9=NULL ;
            sinfo_interleave_frames(im_obj,&im_dither, cfg->noRows, &im9);
            sinfo_pro_save_ima(im9, raw, sof, cfg->outName, frm_pro_ctg, NULL,
                                   plugin_id, config);
            sinfo_free_image(&im9);
        }

        /*
    #---------------------------------------------------------
    # convolve spectra with Gaussian
    #---------------------------------------------------------
         */
    } else if (cfg->gaussInd == 1 && cfg->interInd == 0) {
        sinfo_msg("Convolve spectra with Gaussian");
        if(pdensity > 1) {
            cknull(im_conv = sinfo_new_convolve_image_by_gauss ( im_obj, cfg->hw ),
                            "sinfo_convolveImageByGauss failed" );

            ck0(sinfo_pro_save_ima(im_conv,raw,sof,cfg->outName,
                            frm_pro_ctg,NULL,plugin_id,config),
                "cannot save ima %s", cfg->outName);

            sinfo_free_image(&im_obj);
            sinfo_free_image(&im_conv);
            if (cfg->contains_dither == 1){
                sinfo_free_image(&im_dither);
            }
        }
    } else {

        cpl_table* qclog_tbl = sinfo_compute_qc(qc, im_obj);
        sinfo_pro_save_ima(im_obj, raw, sof, cfg->outName, frm_pro_ctg,
                           qclog_tbl, plugin_id, config);
        sinfo_free_table(&qclog_tbl);
        sinfo_free_image(&im_obj);
        if (cfg->contains_dither == 1 && cfg->interInd == 0) {
              if (strstr(cfg->outName, ".fits") != NULL) {
                  snprintf(name_list, MAX_NAME_SIZE - 1, "%s%s",
                                  sinfo_new_get_rootname(cfg->outName),
                                  "_dith.fits");
                  strcpy(cfg->outName, name_list);
              }
              else {
                  strcat(cfg->outName, "_dith");
              }
              cpl_free(name_list);

              sinfo_pro_save_ima(im_dither, raw, sof, cfg->outName, frm_pro_ctg,
                                 NULL,plugin_id,config);

              if (cfg->contains_dither == 1) {
                  sinfo_free_image(&im_dither);
              }
          }
    }

    /* the following generates a valgrind error
     but without it 8 bytes are leaked */
    sinfo_free_image_array(&im,cfg->nframes);

    /*AMO: check if those images can be deleted before */
    sinfo_free_image(&int_im_shifted);
    sinfo_free_image(&im_obj_flat);

    sinfo_stack_free(&cfg);
    sinfo_free_frameset(&raw);
    sinfo_qc_wcal_delete(&qc);

    return 0;

    cleanup:
    sinfo_free_table(&tbl_slitpos);
    sinfo_free_table(&tbl_index);
    if(slit_edges!=NULL) sinfo_new_destroy_2Dfloatarray(&slit_edges, 32);
    sinfo_free_image(&flat1);
    sinfo_free_image(&flat_smooth);
    sinfo_free_image(&int_im_shifted);
    sinfo_free_image(&im_dither);
    sinfo_free_image(&flat2);
    sinfo_free_image(&im_obj_flat);
    sinfo_free_image(&im_obj);
    sinfo_free_image(&mask_im);
    sinfo_free_image(&im_sky);
    sinfo_free_imagelist(&list_object_tmp);
    sinfo_free_image(&sky_img_flat);
    sinfo_free_image(&sky_dist);
    sinfo_free_image(&sky_img);
    sinfo_free_imagelist(&list_object);
    sinfo_free_imagelist(&list_sky);
    if(im != NULL) sinfo_free_image_array(&im,cfg->nframes);
    sinfo_stack_free(&cfg);
    sinfo_free_frameset(&raw);
    sinfo_qc_wcal_delete(&qc);

    return -1 ;

}
/**@}*/
