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

}


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;
    new_Lookup* lookup=NULL;
    cpl_image * im3=NULL ;
    cpl_image * im4=NULL ;
    cpl_image * im5=NULL ;
    cpl_image * im6=NULL ;
    cpl_image * im7=NULL ;
    cpl_image * im8=NULL ;
    cpl_image * im9=NULL ;

    cpl_image * ref_im1=NULL ;
    cpl_image * ref_im2=NULL ;
    cpl_image ** im=NULL ;
    cpl_image * im_obj=NULL ;
    cpl_image* simg=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_sub=NULL ;
    cpl_image * im_obj_flat=NULL ;
    cpl_image * im_dither_sub=NULL ;
    cpl_image * im_dither_flat=NULL ;
    cpl_image * int_im_shifted=NULL ;
    cpl_image * int_im_dith_shifted=NULL ;
    cpl_image * im_conv=NULL ;
    int sy=0;

    cpl_image * mask_im=NULL ;
    cpl_image * flat_smooth=NULL ;
    cpl_image * flat1=NULL ;
    cpl_image * flat2=NULL ;
    cpl_image * int_im=NULL ;
    cpl_image * int_im_dith=NULL ;
    cpl_image * sky_img_flat=NULL;
    cpl_image * sky_dist=NULL;


    cpl_imagelist * iCube=NULL ;
    cpl_imagelist * jCube=NULL ;
    cpl_image * X=NULL ;
    cpl_image * hX=NULL ;
    cpl_image * Y=NULL ;
    cpl_image * Z=NULL ;
    cpl_table * qclog_tbl=NULL;
    cpl_image* sky_img=NULL;
    cpl_image* mdark=NULL;

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

    float** slit_edges=NULL;
    char** in_nam=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_image* flat1_dist=NULL;
    cpl_image* flat2_dist=NULL;

    cpl_frameset* raw=NULL;

    char file_name[MAX_NAME_SIZE];
    cpl_table* tbl_index = NULL;
    cpl_table* tbl_slitpos=NULL;
    /* int rhead=0; */

    cpl_frame*     sky_frame = NULL;
    char* sky_name  = NULL;
    /* 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)) {
                    check_nomsg(sky_frame = cpl_frameset_get_frame(raw,i));
                    check_nomsg(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) ) {
                        check_nomsg(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");
                        ck0(sinfo_pro_save_ima(sky_img,raw,sof,sky_name,
                                        PRO_SKY_STACKED_DUMMY,NULL,
                                        plugin_id,config),
                            "cannot save sky ima %s", sky_name);

                        sinfo_free_image(&sky_img);
                        if (cfg->flatInd == 1) {
                            sinfo_msg("Sky Flatfielding");
                            check(flat1=cpl_image_load(cfg->flatfield1,CPL_TYPE_FLOAT,0,0 ),
                                  "could not load flatfield image" );

                            if(mflat_norm_smooth != 0) {

                                if(mflat_norm_smooth == 1) {

                                    sy=cpl_image_get_size_y(flat1);

                                    cknull(flat_smooth=sinfo_image_smooth_fft(flat1,sy/smooth_rad),
                                           "could not smooth flatfield" );
                                } else if(mflat_norm_smooth == 2) {
                                    cknull(flat_smooth = sinfo_image_smooth_median_y(flat1,
                                                    smooth_rad),
                                                    "could not smooth flatfield" );
                                }

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

                            }

                            check_nomsg(simg = cpl_image_load(sky_name,CPL_TYPE_FLOAT,0,0 ));

                            cknull(sky_img_flat=sinfo_new_div_images_robust(simg,flat1),
                                   "could not carry out flatfield division" );
                            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");
                                sky_dist = sinfo_new_image_warp_fits(sky_img_flat,
                                                cfg->kernel,
                                                cfg->polyFile);

                                ck0(sinfo_pro_save_ima(sky_dist,raw,sof,
                                                file_name,
                                                PRO_STACK_SKY_DIST,NULL,plugin_id,
                                                config),"cannot save ima %s",
                                    STACK_SKY_DIST_OUT_FILENAME);

                                sinfo_free_image(&sky_dist);
                            }
                            /* } */
                            sinfo_free_image(&sky_img_flat);
                        } /* end check on flatind */
                    } /* end check on procatg */
                }
            } 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 ) {
        if (cfg->contains_sky == 1) {
            sinfo_msg("Subtract the off-frame (sky) from the on-frame");
            check_nomsg(im_obj_sub = cpl_image_duplicate(im_obj));
            check(cpl_image_subtract(im_obj_sub, im_sky),
                  "could not sinfo_sub_image");

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

        if (cfg->contains_dither == 1 && nskydith > 0) {
            check_nomsg(im_dither_sub = cpl_image_duplicate(im_dither));
            check(cpl_image_subtract(im_dither_sub, im_dither_sky),
                  "could not sinfo_sub_image");

            sinfo_free_image(&im_dither);
            sinfo_free_image(&im_dither_sky);
            im_dither = cpl_image_duplicate(im_dither_sub);

        } else if (cfg->contains_dither == 1 &&
                        nskydith == 0 &&
                        cfg->contains_sky == 1) {
            check_nomsg(im_dither_sub = cpl_image_duplicate(im_dither));
            check(cpl_image_subtract(im_dither_sub, im_sky),
                  "could not sinfo_sub_image");

            sinfo_free_image(&im_dither);
            sinfo_free_image(&im_sky);
            im_dither = cpl_image_duplicate(im_dither_sub);
        }
    }

    /*
  #---------------------------------------------------------
  # Flatfielding
  #---------------------------------------------------------
     */

    if (cfg->flatInd == 1) {
        sinfo_msg("Flatfielding");
        check(flat1 = cpl_image_load (cfg->flatfield1,CPL_TYPE_FLOAT,0,0),
              "could not load flatfield image" );

        if(mflat_norm_smooth) {

            //We normalize the flat by a smoothed flat
            cknull(flat_smooth = sinfo_image_smooth_median_y(flat1,smooth_rad),
                            "could not smooth flatfield" );
            check_nomsg(cpl_image_divide(flat1,flat_smooth));
            sinfo_free_image(&flat_smooth);
        }

        cknull(im_obj_flat = sinfo_new_div_images_robust( im_obj, flat1),
               "could not carry out flatfield division" );

        /* AMO ** */
        if(pdensity > 1) {
            if (frm_ind == 0) {
                if (cfg->warpfixInd == 1){
                    sinfo_msg("Correct FF for distortions");
                    /* AMO check */
                    cknull_nomsg(flat1_dist=sinfo_new_image_warp_fits(flat1,cfg->kernel,
                                    cfg->polyFile));

                    ck0(sinfo_pro_save_ima(flat1_dist,raw,sof,
                                    STACK_MFLAT_DIST_OUT_FILENAME,
                                    PRO_STACK_MFLAT_DIST,NULL,plugin_id,config),
                        "cannot save ima %s", STACK_MFLAT_DIST_OUT_FILENAME);
                    sinfo_free_image(&flat1_dist);
                }
            }
        }
        sinfo_free_image(&flat1);
        sinfo_free_image(&im_obj);
        im_obj = cpl_image_duplicate(im_obj_flat);

        if(pdensity > 1) {
            if (cfg->contains_dither == 1) {
                check(flat2 = cpl_image_load (cfg->flatfield2,CPL_TYPE_FLOAT,0,0),
                                "could not load flatfield image" );

                if(mflat_norm_smooth) {

                    //We normalize the flat by a smoothed flat
                    cknull(flat_smooth = sinfo_image_smooth_median_y(flat2,smooth_rad),
                                    "could not smooth flatfield" );
                    check_nomsg(cpl_image_divide(flat2,flat_smooth));
                    sinfo_free_image(&flat_smooth);

                }


                cknull(im_dither_flat = sinfo_new_div_images_robust( im_dither, flat2),
                       "could not carry out flatfield division" );

                if (frm_ind == 0) {
                    if (cfg->warpfixInd == 1) {
                        sinfo_msg("Correct FF for distortions");
                        flat2_dist = sinfo_new_image_warp_fits(flat2,
                                        cfg->kernel, cfg->polyFile);

                        ck0(sinfo_pro_save_ima(flat2_dist,raw,sof,
                                        STACK_MFLAT_DITHER_DIST_OUT_FILENAME,
                                        PRO_STACK_MFLAT_DITHER_DIST,
                                        NULL,plugin_id,config),
                            "cannot save ima %s", STACK_MFLAT_DITHER_DIST_OUT_FILENAME);
                        sinfo_free_image(&flat2_dist);
                    }
                }
                sinfo_free_image(&flat2);
                sinfo_free_image(&im_dither);
                im_dither = cpl_image_duplicate(im_dither_flat);
            }
        }
    }

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

    if (cfg->maskInd == 1) {
        sinfo_msg("Static bad pixel correction");
        check(mask_im = cpl_image_load(cfg->mask,CPL_TYPE_FLOAT,0,0),
              "could not load static bad pixel mask" );

        ck0(sinfo_new_change_mask(mask_im, im_obj),
            "sinfo_changeMask failed" );

        if (cfg->indind == 0) {
            /* open the ASCII list of the slitlet positions */
            /*READ TFITS TABLE*/
            strcpy(file_name,cfg->slitposList);
            check(tbl_slitpos = cpl_table_load(file_name,1,0),
                  "error loading slitpos tbl %s ",file_name);
            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);
                goto cleanup;
            }
            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);
                goto cleanup;
            }

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

            sinfo_free_table(&tbl_slitpos);
            cknull(int_im = sinfo_interpol_source_image (im_obj,
                            mask_im,
                            cfg->maxRad,
                            slit_edges),
                   "could not carry out sinfo_interpolSourceImage" );

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

            if (cfg->contains_dither == 1) {
                cknull(int_im_dith = sinfo_interpol_source_image (im_dither,
                                mask_im,
                                cfg->maxRad,
                                slit_edges),
                                "could not carry out sinfo_interpolSourceImage" );

                sinfo_free_image(&im_dither);
                im_dither = cpl_image_duplicate(int_im_dith);
            }
            sinfo_new_destroy_2Dfloatarray(&slit_edges, 32);
        } else {
            cknull(int_im = sinfo_new_mult_image_by_mask(im_obj, mask_im),
                            "could not carry out sinfo_multImageByMask" );

            sinfo_free_image(&im_obj);
            im_obj = cpl_image_duplicate(int_im);
            if (cfg->contains_dither == 1) {
                cknull(int_im_dith=sinfo_new_mult_image_by_mask(im_dither, mask_im),
                                "could not carry out sinfo_multImageByMask" );

                sinfo_free_image(&im_dither);
                im_dither = cpl_image_duplicate(int_im_dith);
            }
        }
        sinfo_free_image(&mask_im);
    }

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

    if (cfg->maskInd == 2){
        sinfo_msg("Static bad pixel correction BEZIER");
        check(mask_im = cpl_image_load(cfg->mask,CPL_TYPE_FLOAT,0,0),
              "could not load static bad pixel mask" );

        ck0(sinfo_new_change_mask(mask_im, im_obj),
            "sinfo_changeMask failed" );

        /* #open the FITS table of the slitlet positions-*/
        strcpy(file_name,cfg->slitposList);
        check_nomsg(tbl_slitpos = cpl_table_load(file_name,1,0));

        check_nomsg(n = cpl_table_get_nrow(tbl_slitpos));
        slit_edges = sinfo_new_2Dfloatarray(n, 2);

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

        strcpy(file_name,cfg->indexlist);

        check_nomsg(tbl_index = cpl_table_load(file_name,1,0));

        check_nomsg(n = cpl_table_get_nrow(tbl_index));

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

        for (i=0;i<cnt;i++) {
            if (strcmp("ICube.fits", name) != 0){
                check_nomsg(iCube=cpl_imagelist_load ("ICube.fits",CPL_TYPE_FLOAT,0));
            }
            else if (strcmp("JCube.fits", name) != 0) {
                check_nomsg(jCube = cpl_imagelist_load ("JCube.fits",CPL_TYPE_FLOAT,0));
            }
            else if (strcmp("X.fits",  name) != 0) {
                check_nomsg(X=cpl_image_load("X.fits",CPL_TYPE_FLOAT,0,0));
            }
            else if (strcmp("Y.fits",  name) != 0) {
                check_nomsg(Y=cpl_image_load("Y.fits",CPL_TYPE_FLOAT,0,0));
            }
            else if (strcmp("Z.fits",  name) != 0) {
                check_nomsg(Z=cpl_image_load("Z.fits",CPL_TYPE_FLOAT,0,0));
            }
            else if (strcmp("cX.fits", name) != 0) {
                check_nomsg(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!");
                goto cleanup;
            }
        }
        lookup = sinfo_new_lookup();

        lookup->id=iCube;
        lookup->jd=jCube;
        lookup->X=X;
        lookup->Y=Y;
        lookup->Z=Z;
        lookup->hX=hX;


        cknull(im_obj=sinfo_new_c_bezier_interpolate_image(im_obj,
                        mask_im,
                        lookup,
                        cfg->maxRad,
                        cfg->maxRad,
                        cfg->maxRad,
                        2,
                        slit_edges),
               "could not carry out sinfo_new_c_bezier_interpolate_image" );


        cknull(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),
               "could not carry out sinfo_new_c_bezier_find_bad" );


        if (cfg->contains_dither == 1) {
            cknull(im_dither=sinfo_new_c_bezier_interpolate_image(im_dither,
                            mask_im,
                            lookup,
                            cfg->maxRad,
                            cfg->maxRad,
                            cfg->maxRad,
                            2,
                            slit_edges),
                            "could not carry out new_c_bezier_Interpolate_Image on dithered frame" );

            cknull(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),
                   "could not carry out new_c_bezier_find_bad on dithered frame");

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

    if (cfg->maskInd == 3) {
        cknull(mask_im = cpl_image_load(cfg->mask,CPL_TYPE_FLOAT,0,0),
                        "could not load static bad pixel mask" );

        /* #open the ASCII list of the slitlet positions-- */
        strcpy(file_name,cfg->slitposList);
        check_nomsg(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);
            goto cleanup;
        }

        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);
            goto cleanup;
        }

        check_nomsg(n = cpl_table_get_nrow(tbl_slitpos));
        slit_edges = sinfo_new_2Dfloatarray(n, 2);

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

        strcpy(file_name,cfg->indexlist);
        check_nomsg(tbl_index = cpl_table_load(file_name,1,0));
        check_nomsg(n = cpl_table_get_nrow(tbl_index));
        cknull_nomsg(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);

        for (i=0;i<cnt;i++){
            if (strcmp("ICube.fits", in_nam[i]) != 0){
                check_nomsg(iCube=cpl_imagelist_load("ICube.fits",CPL_TYPE_FLOAT,0));
            }
            else if (strcmp("JCube.fits", in_nam[i]) != 0){
                check_nomsg(jCube=cpl_imagelist_load("JCube.fits",CPL_TYPE_FLOAT,0));
            }
            else if (strcmp("X.fits", in_nam[i]) != 0){
                check_nomsg(X=cpl_image_load("X.fits",CPL_TYPE_FLOAT,0,0));
            }
            else if (strcmp("Y.fits", in_nam[i]) != 0){
                check_nomsg(Y=cpl_image_load("Y.fits",CPL_TYPE_FLOAT,0,0));
            }
            else if (strcmp("Z.fits", in_nam[i]) != 0){
                check_nomsg(Z=cpl_image_load("Z.fits",CPL_TYPE_FLOAT,0,0));
            }
            else if (strcmp("cX.fits", in_nam[i]) != 0) {
                check_nomsg(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!");
                goto cleanup;
            }
        }
        lookup = sinfo_new_lookup();
        lookup->id=iCube;
        lookup->jd=jCube;
        lookup->X=X;
        lookup->Y=Y;
        lookup->Z=Z;
        lookup->hX=hX;

        cknull(im_obj = sinfo_new_c_bezier_interpolate_image(im_obj,
                        mask_im,
                        lookup,
                        cfg->maxRad,
                        cfg->maxRad,
                        cfg->maxRad,
                        2,
                        slit_edges ),
               "could not carry out sinfo_new_c_bezier_interpolate_image" );

        if (cfg->contains_dither == 1) {
            cknull(im_dither=sinfo_new_c_bezier_interpolate_image( im_dither,
                            mask_im,
                            lookup,
                            cfg->maxRad,
                            cfg->maxRad,
                            cfg->maxRad,
                            2,
                            slit_edges ),
                            "could not carry out sinfo_new_c_bezier_interpolate_image"
                            " on dithered frame" );

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


    /*
  #---------------------------------------------------------
  # 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) {
            sinfo_msg("Merge (interleave) frames");
            cknull(im3 = cpl_image_new(cpl_image_get_size_x(im_obj),
                            cpl_image_get_size_y(im_obj),CPL_TYPE_FLOAT),
                   "could not allocate an image" );
            cknull(im4=sinfo_new_remove_general_offset( im_obj, im_dither,
                            im3, cfg->noRows ),
                   "sinfo_removeGeneralOffset failed" );

            cknull(im5 = sinfo_new_remove_regional_tilt ( im_obj, im4, im3 ),
                   "sinfo_removeRegionalTilt failed" );

            cknull(im6 = sinfo_new_remove_column_offset ( im_obj, im5, im3 ),
                   "sinfo_removeColumnOffset failed" );

            cknull(im7 = sinfo_new_remove_residual_tilt ( im6, im3 ),
                   "sinfo_removeResidualTilt failed" );

            cknull(im8 = sinfo_new_remove_residual_offset ( im7, im3 ),
                   "sinfo_removeResidualOffset failed");
            cknull(im9 = sinfo_sinfo_merge_images(im_obj, im8, im3),
                   "sinfo_mergeImages failed" );

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

            sinfo_free_image(&im3);
            sinfo_free_image(&im4);
            sinfo_free_image(&im5);
            sinfo_free_image(&im6);
            sinfo_free_image(&im7);
            sinfo_free_image(&im8);
            sinfo_free_image(&im9);
            sinfo_free_image(&im_obj);
            sinfo_free_image(&im_dither);
        }
        /*
    #---------------------------------------------------------
    # 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 {

        sinfo_msg("Add QC LOG");
        /* add QC-LOG */
        /* sinfo_det_ncounts(raw, cfg->qc_thresh_max); */
        cknull_nomsg(qclog_tbl = sinfo_qclog_init());

        ck0_nomsg(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"));*/
        ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC FRMOFF MEANFLUX",
                        qc->avg_of,"Average of flux","%g"));
        ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC FRMDIF MEANFLUX",
                        qc->avg_di,"Average of flux","%g"));
        ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC FRMON MAXFLUX",
                        qc->max_on,"Max of flux","%g"));
        ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC FRMOFF MAXFLUX",
                        qc->max_of,"Max of flux","%g"));
        ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC FRMDIF MAXFLUX",
                        qc->max_di,"Max of flux","%g"));
        ck0_nomsg(sinfo_qclog_add_int(qclog_tbl,"QC FRMON NPIXSAT",
                        qc->nsat,
                        "Number of saturated pixels","%d"));
        update_bad_pixel_map(im_obj);
        ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC FRMDIF MEANSTD",
                        cpl_image_get_mean(im_obj),"mean of the image","%13.6f"));

        ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,
                        "QC FRMDIF STDEV",
                        cpl_image_get_stdev(im_obj),
                        "standard deviation of the image",
                        "%13.6f"));

        ck0(sinfo_pro_save_ima(im_obj,raw,sof,cfg->outName,
                        frm_pro_ctg,qclog_tbl,plugin_id,config),
            "cannot dump ima %s", cfg->outName);

        sinfo_free_image(&im_obj);
        sinfo_free_table(&qclog_tbl);

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



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

            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(&int_im);
    sinfo_free_image(&im_obj_flat);
    sinfo_free_image(&im_obj_sub);

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

    return 0;

    cleanup:
    sinfo_free_table(&qclog_tbl);
    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_dist);
    sinfo_free_image(&flat1);
    sinfo_free_image(&flat_smooth);
    sinfo_free_image(&flat2_dist);
    sinfo_free_image(&int_im);
    sinfo_free_image(&int_im_dith);
    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_sub);
    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 ;

}
/**@}*/
