/*
 * 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_stdstar.c
   Author       :    J. Schreiber
   Created on   :    December 3, 2003
   Description  :    this routine doess the optimal extraction of a spectrum
                        of an already reduced data cube of a standard star
                        observation. Additionally, a conversion factor from
                        mag to counts/sec can be determined if the magnitude
                        of the standard star is known.
                        This is done for a number of jittered data cubes and
                        the results are averaged by rejecting the extreme
                        values

 ---------------------------------------------------------------------------*/

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

//Used only for cpl_propertylist_has
#include <irplib_stdstar.h>
#include <sinfo_cpl_size.h>
#include "irplib_utils.h"
#include "sinfo_dfs.h"
#include "sinfo_tpl_utils.h"

#include "sinfo_new_stdstar.h"
#include "sinfo_standstar_ini_by_cpl.h"
#include "sinfo_pro_save.h"
#include "sinfo_pfits.h"
#include "sinfo_utilities_scired.h"
#include "sinfo_spectrum_ops.h"
#include "sinfo_hidden.h"
#include "sinfo_functions.h"
#include "sinfo_utl_efficiency.h"
#include "sinfo_error.h"
#include "sinfo_utils_wrappers.h"
/*----------------------------------------------------------------------------
                                Defines
 ---------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/**
 * @internal
 * @brief    Find the aperture(s) with the greatest flux
 * @param    self   The aperture object
 * @param    ind  The aperture-indices in order of decreasing flux
 * @param    nfind  Number of indices to find
 * @return   CPL_ERROR_NONE or the relevant _cpl_error_code_ on error
 *
 * nfind must be at least 1 and at most the size of the aperture object.
 *
 * The ind array must be able to hold (at least) nfind integers.
 * On success the first nfind elements of ind point to indices of the
 * aperture object.
 *
 * To find the single ind of the aperture with the maximum flux use simply:
 * int ind;
 * sinfo_apertures_find_max_flux(self, &ind, 1);
 *
 */
/*----------------------------------------------------------------------------*/
static cpl_error_code sinfo_apertures_find_max_flux(const cpl_apertures * self,
                                              int * ind, int nfind)
{
    const int    nsize = cpl_apertures_get_size(self);
    int          ifind;


    cpl_ensure_code(nsize > 0,      cpl_error_get_code());
    cpl_ensure_code(ind,          CPL_ERROR_NULL_INPUT);
    cpl_ensure_code(nfind > 0,      CPL_ERROR_ILLEGAL_INPUT);
    cpl_ensure_code(nfind <= nsize, CPL_ERROR_ILLEGAL_INPUT);

    for (ifind=0; ifind < nfind; ifind++) {
        double maxflux = -1;
        int maxind = -1;
        int i;
        for (i=1; i <= nsize; i++) {
            int k;

            /* The flux has to be the highest among those not already found */
            for (k=0; k < ifind; k++) if (ind[k] == i) break;

            if (k == ifind) {
                /* i has not been inserted into ind */
                const double flux = cpl_apertures_get_flux(self, i);

                if (maxind < 0 || flux > maxflux) {
                    maxind = i;
                    maxflux = flux;
                }
            }
        }
        ind[ifind] = maxind;
    }

    return CPL_ERROR_NONE;

}
/*----------------------------------------------------------------------------*/
/**
 * @internal
 * @brief    Find the peak flux, peak sum and position of a Gaussian
 * @param    self        Image to process
 * @param    sigma       The initial detection level  [ADU]
 * @param    pxpos       On success, the refined X-position [pixel]
 * @param    pypos       On success, the refined Y-position [pixel]
 * @param    ppeak       On success, the refined peak flux  [ADU]
 * @return CPL_ERROR_NONE or the relevant CPL error code on error
 *
 * The routine initially determines the approximate position and flux value of
 * the PSF with a robust Gaussian fit: first are identified all sources that lie
 * 5 sigmas above the median of the image, then is determined the position of
 * the barycenter of the region with highest peak. Finally is performed the fit
 * of a Gaussian centered on the found barycenter position.
 *
 */
/*----------------------------------------------------------------------------*/
static cpl_error_code
sinfo_gaussian_maxpos(const cpl_image * self,
                double sigma,
                double  * pxpos,
                double  * pypos,
                double  * ppeak)
{
    /* copied from irplib_strehl.c r163170 */
    const cpl_size  nx = cpl_image_get_size_x(self);
    const cpl_size  ny = cpl_image_get_size_y(self);
    int             iretry = 3; /* Number retries with decreasing sigma */
    int             ifluxapert = 0;
    double          med_dist;
    const double    median = cpl_image_get_median_dev(self, &med_dist);
    cpl_mask      * selection;
    cpl_size        nlabels = 0;
    cpl_image     * labels = NULL;
    cpl_apertures * aperts;
    cpl_size        npixobj;
    double          objradius;
    cpl_size        winsize;
    cpl_size        xposmax, yposmax;
    double          xposcen, yposcen;
    double          valmax, valfit = -1.0;
    cpl_array     * gauss_parameters = NULL;
    cpl_errorstate  prestate = cpl_errorstate_get();
    cpl_error_code  code = CPL_ERROR_NONE;


    cpl_ensure_code( sigma > 0.0, CPL_ERROR_ILLEGAL_INPUT);

    selection = cpl_mask_new(nx, ny);

    /* find aperture with signal larger than sigma * median deviation */
    for (; iretry > 0 && nlabels == 0; iretry--, sigma *= 0.5) {

        /* Compute the threshold */
        const double threshold = median + sigma * med_dist;


        /* Select the pixel above the threshold */
        code = cpl_mask_threshold_image(selection, self, threshold, DBL_MAX,
                                        CPL_BINARY_1);

        if (code) break;

        /* Labelise the thresholded selection */
        cpl_image_delete(labels);
        labels = cpl_image_labelise_mask_create(selection, &nlabels);
    }
    sigma *= 2.0; /* reverse last iteration that found no labels */

    cpl_mask_delete(selection);

    if (code) {
        cpl_image_delete(labels);
        return cpl_error_set_where(cpl_func);
    } else if (nlabels == 0) {
        cpl_image_delete(labels);
        return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
    }

    aperts = cpl_apertures_new_from_image(self, labels);

    /* Find the aperture with the greatest flux */
    code = sinfo_apertures_find_max_flux(aperts, &ifluxapert, 1);

    if (code) {
        cpl_apertures_delete(aperts);
        cpl_image_delete(labels);
        return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
    }

    npixobj = cpl_apertures_get_npix(aperts, ifluxapert);
    objradius = sqrt((double)npixobj * CPL_MATH_1_PI);
    winsize = CX_MIN(CX_MIN(nx, ny), (3.0 * objradius));

    xposmax = cpl_apertures_get_maxpos_x(aperts, ifluxapert);
    yposmax = cpl_apertures_get_maxpos_y(aperts, ifluxapert);
    xposcen = cpl_apertures_get_centroid_x(aperts, ifluxapert);
    yposcen = cpl_apertures_get_centroid_y(aperts, ifluxapert);
    valmax  = cpl_apertures_get_max(aperts, ifluxapert);

    cpl_apertures_delete(aperts);
    cpl_image_delete(labels);

    cpl_msg_debug(cpl_func, "Object radius at S/R=%g: %g (window-size=%u)",
                  sigma, objradius, (unsigned)winsize);
    cpl_msg_debug(cpl_func, "Object-peak @ (%d, %d) = %g", (int)xposmax,
                  (int)yposmax, valmax);

    /* fit gaussian to get subpixel peak position */

    gauss_parameters = cpl_array_new(7, CPL_TYPE_DOUBLE);
    cpl_array_set_double(gauss_parameters, 0, median);

    code = cpl_fit_image_gaussian(self, NULL, xposmax, yposmax,
                                  winsize, winsize, gauss_parameters,
                                  NULL, NULL, NULL,
                                  NULL, NULL, NULL,
                                  NULL, NULL, NULL);
    if (!code) {
        const double M_x = cpl_array_get_double(gauss_parameters, 3, NULL);
        const double M_y = cpl_array_get_double(gauss_parameters, 4, NULL);

        valfit = cpl_gaussian_eval_2d(gauss_parameters, M_x, M_y);

        if (!cpl_errorstate_is_equal(prestate)) {
            code = cpl_error_get_code();
        } else {
            *pxpos        = M_x;
            *pypos        = M_y;
            *ppeak        = valfit;

            cpl_msg_debug(cpl_func, "Gauss-fit @ (%g, %g) = %g",
                          M_x, M_y, valfit);
        }
    }
    cpl_array_delete(gauss_parameters);

    if (code || valfit < valmax) {
        cpl_errorstate_set(prestate);
        *pxpos   = xposcen;
        *pypos   = yposcen;
        *ppeak   = valmax;
    }

    return code ? cpl_error_set_where(cpl_func) : CPL_ERROR_NONE;
}
cpl_mask * sinfo_bpm_filter(
        const cpl_mask    *   input_mask,
        cpl_size        kernel_nx,
        cpl_size        kernel_ny,
        cpl_filter_mode filter)
{
    cpl_mask * kernel = NULL;
    cpl_mask * filtered_mask = NULL;
    cpl_mask * expanded_mask = NULL;
    cpl_mask * expanded_filtered_mask = NULL;

    /* Check Entries */
    cpl_ensure(input_mask != NULL, CPL_ERROR_NULL_INPUT, NULL);
    cpl_ensure(kernel_nx >= 1, CPL_ERROR_ILLEGAL_INPUT, NULL);
    cpl_ensure(kernel_ny >= 1, CPL_ERROR_ILLEGAL_INPUT, NULL);
    cpl_ensure(filter == CPL_FILTER_EROSION || filter == CPL_FILTER_DILATION ||
            filter == CPL_FILTER_OPENING || filter == CPL_FILTER_CLOSING,
            CPL_ERROR_ILLEGAL_INPUT, NULL);

    /* Only odd-sized masks allowed */
    cpl_ensure((kernel_nx&1) == 1, CPL_ERROR_ILLEGAL_INPUT, NULL);
    cpl_ensure((kernel_ny&1) == 1, CPL_ERROR_ILLEGAL_INPUT, NULL);

    kernel = cpl_mask_new(kernel_nx, kernel_ny);
    cpl_mask_not(kernel); /* All values set to unity*/

    /* Enlarge the original mask with the kernel size and assume that outside
     * all pixels are good */
    expanded_mask = cpl_mask_new(
            cpl_mask_get_size_x(input_mask) + 2 * kernel_nx,
            cpl_mask_get_size_y(input_mask) + 2 * kernel_ny);

    cpl_mask_copy(expanded_mask, input_mask, kernel_nx + 1, kernel_ny +1 );

    expanded_filtered_mask = cpl_mask_new(cpl_mask_get_size_x(expanded_mask),
            cpl_mask_get_size_y(expanded_mask));

    if(cpl_mask_filter(expanded_filtered_mask, expanded_mask, kernel, filter,
                    CPL_BORDER_ZERO) != CPL_ERROR_NONE) {

        cpl_mask_delete(kernel);
        cpl_mask_delete(expanded_filtered_mask);
        cpl_mask_delete(expanded_mask);
        return NULL;
    }

    /* Extract the original mask from the expanded mask */
    filtered_mask = cpl_mask_extract(expanded_filtered_mask,
            kernel_nx+1, kernel_ny + 1,
            cpl_mask_get_size_x(input_mask) + kernel_nx,
            cpl_mask_get_size_y(input_mask) + kernel_ny);


    /* Free memory */
    cpl_mask_delete(kernel);
    cpl_mask_delete(expanded_filtered_mask);
    cpl_mask_delete(expanded_mask);

    return filtered_mask;
}

static cpl_mask*
sinfo_object_mask(cpl_image* std_med_ima, const char* pfm, const int pfx,
                  const int pfy, const double kappa)
{
    cpl_mask* object_mask;
    double mad;
    double median;
    cpl_mask* nan_mask;
    /* flag NAN in image (due to SINFONI BP conventions) before computing mad */
    cpl_image_reject_value(std_med_ima,CPL_VALUE_NAN);
    /* extract mask of NANs to be used later */
    nan_mask=cpl_image_get_bpm(std_med_ima);
    //cpl_mask_save(nan_mask,"nan_mask.fits",NULL,CPL_IO_CREATE);
    median = cpl_image_get_mad(std_med_ima, &mad);
    double low_cut= median - 10 * kappa * mad * CPL_MATH_STD_MAD;
    double hi_cut= median + kappa * mad * CPL_MATH_STD_MAD;
    /* takes as low cut a very small value to be sure to get all negative pixels
     * as good */
    low_cut=-1.e10;
    //sinfo_msg("median: %g mad: %g low: %g hi : %g", median, mad, low_cut, hi_cut);
    /* detect object (and other previously flagged values) as good pixels */
    object_mask=cpl_mask_threshold_image_create(std_med_ima, low_cut, hi_cut);
    //cpl_mask_not(object_mask);

    //cpl_mask_save(object_mask,"object_mask.fits",NULL,CPL_IO_CREATE);
    /* to detect only object pixels as good one make or with previously flagged
     * NAN values
     */

    cpl_mask_or(object_mask,nan_mask);
    //cpl_mask_save(object_mask,"or_mask.fits",NULL,CPL_IO_CREATE);
    /* increase the mask of a few pixels to be sure to include all object values
     * for this reason we use method dilation and we make a NOT on the image
     * because the DILATION enlarge the area of BAD pixels, not the GOOD ones
     * but we want to increase the area covered by the object (flagged as good)
     */
    cpl_filter_mode filter_mode = CPL_FILTER_EROSION ;
    //sinfo_msg_warning("pfm=%s",pfm);
    if( strcmp(pfm,"erosion") == 0 ) {
        sinfo_msg("Filter erosion");
        filter_mode = CPL_FILTER_EROSION ;
    } else if( strcmp(pfm,"dilation") == 0 ) {
        sinfo_msg("Filter dilation");
        filter_mode = CPL_FILTER_DILATION ;
    } else if( strcmp(pfm,"closing") == 0 ) {
        sinfo_msg("Filter closing");
        filter_mode = CPL_FILTER_CLOSING ;
    }
    //cpl_filter_mode filter_mode = CPL_FILTER_DILATION ;

    cpl_mask_not(object_mask);
    cpl_mask*  obj_mask_filtered=sinfo_bpm_filter(object_mask, pfx, pfy, filter_mode);
    /* To have again a proper mask with object flagged as good we do a NOT */
    cpl_mask_not(obj_mask_filtered);
    //cpl_mask_save(obj_mask_filtered,"filtered_mask.fits",NULL,CPL_IO_CREATE);
    /* clean-up memory */
    cpl_mask_delete(object_mask);
    //cpl_mask_delete(nan_mask);
    return obj_mask_filtered;
}

cpl_image *
sinfo_simple_extraction_from_cube(cpl_imagelist * cube, cpl_mask* obj_mask,
                                  const char* name,
                                  cpl_table** spectrum,
                                  int qc_info,
                                  int* check2){

    cpl_image * retIm ;

    int sz=cpl_imagelist_get_size(cube);
    float* podata=NULL;
    double gfit_par[7] ;
    float dispersion = 0;
    float lambda_start=0;
    float cenpix = 0;
    float cenLambda = 0;
    cpl_propertylist* plist;
    int nima=cpl_image_get_size_x(obj_mask)*cpl_image_get_size_y(obj_mask);

    cpl_mask* sky_mask=cpl_mask_duplicate(obj_mask);
    cpl_mask_not(sky_mask);
    //cpl_mask_save(sky_mask,"sky_mask.fits",NULL,CPL_IO_CREATE);
    //cpl_mask_save(obj_mask,"obj_mask.fits",NULL,CPL_IO_CREATE);

    plist=cpl_propertylist_load(name,0);
    cenpix = sinfo_pfits_get_crpix3(plist);
    cenLambda = sinfo_pfits_get_crval3(plist);
    dispersion = sinfo_pfits_get_cdelt3(plist);
    cpl_propertylist_delete(plist);
    lambda_start=cenLambda-cenpix*dispersion;

    cpl_table_new_column(*spectrum,"wavelength", CPL_TYPE_FLOAT);
    cpl_table_new_column(*spectrum,"counts_tot" , CPL_TYPE_FLOAT);
    cpl_table_new_column(*spectrum,"counts_bkg" , CPL_TYPE_FLOAT);
    cpl_table_new_column(*spectrum,"bkg_tot" , CPL_TYPE_FLOAT);

    if(qc_info==1) {
        cpl_table_new_column(*spectrum,"AMP" , CPL_TYPE_FLOAT);
        cpl_table_new_column(*spectrum,"XC" , CPL_TYPE_FLOAT);
        cpl_table_new_column(*spectrum,"YC" , CPL_TYPE_FLOAT);
        cpl_table_new_column(*spectrum,"BKG" , CPL_TYPE_FLOAT);
        cpl_table_new_column(*spectrum,"FWHMX" , CPL_TYPE_FLOAT);
        cpl_table_new_column(*spectrum,"FWHMY" , CPL_TYPE_FLOAT);
        cpl_table_new_column(*spectrum,"ANGLE" , CPL_TYPE_FLOAT);
    }
    retIm = cpl_image_new(1, sz,CPL_TYPE_FLOAT);
    podata=cpl_image_get_data_float(retIm);


    for(int z=0; z< sz; z++){
        cpl_image* i_img=cpl_imagelist_get(cube,z);
        //cpl_image_save(i_img, "i_img.fits", CPL_BPP_IEEE_FLOAT,NULL, CPL_IO_DEFAULT);
        float* pidata=cpl_image_get_data_float(i_img);
        float weighted_sum = 0. ;
        float counts_tot=0.;
        float counts_bkg=0.;
        float bkg_tot=0.;
        float sky_med=0;
        int nbad_sky=0;
        int nbad_obj=0;
        cpl_mask* nan_mask_tmp;
        cpl_mask* sky_mask_tmp=cpl_mask_duplicate(sky_mask);
        cpl_mask* obj_mask_tmp=cpl_mask_duplicate(obj_mask);
        int obj_numb;

        /* flag NAN in image (SINFONI BP conventions) before getting med */
        //cpl_image_reject_value(i_img,CPL_VALUE_NAN);
        /* extract mask of NANs to be used later */
        cpl_image_reject_value(i_img,CPL_VALUE_NAN);
        nan_mask_tmp=cpl_image_get_bpm(i_img);
        //cpl_mask_save(nan_mask_tmp,"nan_mask_tmp.fits",NULL,CPL_IO_CREATE);

        /* include flagged pixels with NAN value in sky mask */
        cpl_mask_or(sky_mask_tmp,nan_mask_tmp);
        //cpl_mask_save(sky_mask_tmp,"sky_mask_tmp.fits",NULL,CPL_IO_CREATE);

        cpl_image_set_bpm(i_img,sky_mask_tmp);
        nbad_sky=cpl_mask_count(sky_mask_tmp);
        if(nbad_sky<nima) {
            check_nomsg(sky_med=cpl_image_get_median(i_img));
            cpl_image_unset_bpm(i_img);
            cpl_image_subtract_scalar(i_img,sky_med);
            //cpl_image_save(i_img, "i_img_sub.fits", CPL_BPP_IEEE_FLOAT,NULL, CPL_IO_DEFAULT);
        }

        cpl_mask_or(obj_mask_tmp,nan_mask_tmp);
        //cpl_mask_save(obj_mask_tmp,"obj_mask_tmp.fits",NULL,CPL_IO_CREATE);

        nbad_obj=cpl_mask_count(obj_mask_tmp);
        if(nbad_obj<nima) {
            cpl_image_set_bpm(i_img,obj_mask_tmp);
            check_nomsg(counts_bkg=cpl_image_get_flux(i_img));
        }
        //cpl_image_save(i_img, "i_img_armin.fits", CPL_BPP_IEEE_FLOAT,NULL, CPL_IO_DEFAULT);
        //cpl_mask_save(cpl_image_get_bpm(i_img),"obj_mask_armin.fits",NULL,CPL_IO_CREATE);

        obj_numb=cpl_mask_count(obj_mask_tmp);
        //cpl_mask_delete(sky_mask_tmp);
        //cpl_mask_delete(obj_mask_tmp);
        bkg_tot=obj_numb*sky_med;
        counts_tot=counts_bkg+bkg_tot;
        weighted_sum=counts_bkg;

        sinfo_msg_debug("z=%d counts_tot: %g counts_bkg: %g sky_med: %g obj_numb: %d bkg_tot: %g",
                  z,counts_tot,counts_bkg,sky_med,obj_numb,bkg_tot);

        podata[z] = weighted_sum ;
        float lambda=lambda_start+z*dispersion;
        cpl_table_set_float(*spectrum,"wavelength" ,z,lambda);
        /* cpl_table_set_float(*spectrum,"intensity" ,z,weighted_sum); */
        cpl_table_set_float(*spectrum,"counts_tot" ,z,counts_tot);
        cpl_table_set_float(*spectrum,"counts_bkg" ,z,counts_bkg);
        cpl_table_set_float(*spectrum,"bkg_tot" ,z,bkg_tot);
        /*
        sinfo_msg_debug("w=%f I=%f b=%f a=%f",
                        lambda,counts_tot,counts_bkg,bkg_tot);
         */
        if(qc_info==1) {
            cpl_table_set_float(*spectrum,"AMP" ,z,gfit_par[0]);
            cpl_table_set_float(*spectrum,"XC" ,z,gfit_par[1]);
            cpl_table_set_float(*spectrum,"YC" ,z,gfit_par[2]);
            cpl_table_set_float(*spectrum,"BKG" ,z,gfit_par[3]);
            cpl_table_set_float(*spectrum,"FWHMX" ,z,gfit_par[4]);
            cpl_table_set_float(*spectrum,"FWHMY" ,z,gfit_par[5]);
            cpl_table_set_float(*spectrum,"ANGLE" ,z,gfit_par[6]);
        }

        if(z==1000) {
            //exit(0);
        }

    }
    cleanup:
    cpl_mask_delete(sky_mask);
    cpl_table_save(*spectrum,NULL,NULL,"spectrum.fits",CPL_IO_DEFAULT);

    return retIm ;

}
/*----------------------------------------------------------------------------
                             Function Definitions
 ---------------------------------------------------------------------------*/
/* temporally commented out as not yet used
static int
sinfo_compute_efficiency(cpl_frameset* sof,
                              const char* name,
			      standstar_config ** cfg,
			      cpl_imagelist  * cube,
			 cpl_table** tbl_spectrum);

*/

/**@{*/
/**
 * @addtogroup sinfo_rec_jitter telluric standard data reduction
 *
 * TBD
 */

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

    cpl_errorstate clean_state = cpl_errorstate_get();
    standstar_config * cfg=NULL ;
    cpl_imagelist  * cube=NULL ;

    cpl_imagelist  * list_object=NULL ;
    cpl_image ** spectrum=NULL ;
    cpl_image * img_spct=NULL ;



    cpl_frameset* raw=NULL;
    cpl_frame* frame=NULL;
    cpl_image* std_med_ima=NULL;
    cpl_image* std_med_dup=NULL;

    cpl_table* qclog_tbl=NULL;
    cpl_table* tbl_spectrum=NULL;
    cpl_propertylist* plist=NULL;
    //char band[FILE_NAME_SZ];

    char * name=NULL ;
    int fra=0;
    float exptime=0 ;
    double convfactor=0;
    double cleanfactor=0;
    float* factor=NULL;

    char std_med_filename[MAX_NAME_SIZE];
    char std_cub_filename[MAX_NAME_SIZE];

    double max_ima_cx=0;
    double max_ima_cy=0;
    cpl_size max_ima_x=0;
    cpl_size max_ima_y=0;
    double norm=0;
    double xcen=0;
    double ycen=0;
    double sig_x=0;
    double sig_y=0;
    double fwhm_x=0;
    double fwhm_y=0;
    double disp=0;
    /* double dispersion=0; */
    int i=0;
    int wllx=0;
    int wlly=0;
    int wurx=0;
    int wury=0;
    int psf_sz=40;
    int qc_info=0;
    int ima_szx=0;
    int ima_szy=0;
    int check1=0;
    int check2=0;
    int check3=0;
    int check4=0;
    double xshift=0;
    double yshift=0;

    float cenpix = 0;
    float cenLambda = 0;

    int no=0;
    double lo_cut=0.;
    double hi_cut=0.;
    /*
    const char* stdstars=NULL;
    const char* sed=NULL;
     */
    cpl_frame* frm_sci=NULL;
    cpl_frame* frm_atmext=NULL;
    cpl_frame* frm_std_cat=NULL;
    cpl_table* tot_eff=NULL;
    double fpar[7];
    double dpar[7];
    int mpar[7];
    int do_compute_eff=0;
    cpl_parameter* p=NULL;
    int pfx=3;
    int pfy=3;
    const char* extract_method;
    const char* pfm;

    //For new way to compute efficiency
    //char band[80];
    //const char  *   seds_file=NULL;
    //const char  *   filter=NULL;
    //cpl_table* tbl_eff=NULL;
    /*
       parse the file names and parameters to the cube_config
       data structure cfg
     */

    /* sinfo_msg("Parse cpl input"); */
    check_nomsg(raw=cpl_frameset_new());

    cknull(cfg=sinfo_parse_cpl_input_standstar(config,sof,&raw),
           "could not parse cpl input!") ;

    cknull_nomsg(p = cpl_parameterlist_find(config,
                    "sinfoni.std_star.compute_eff"));
    check_nomsg(do_compute_eff = cpl_parameter_get_bool(p));


    cknull_nomsg(p = cpl_parameterlist_find(config,
                    "sinfoni.std_star.extract"));
    check_nomsg(extract_method = cpl_parameter_get_string(p));

    cknull_nomsg(p = cpl_parameterlist_find(config,
                    "sinfoni.std_star.pfm"));
    check_nomsg(pfm = cpl_parameter_get_string(p));

    cknull_nomsg(p = cpl_parameterlist_find(config,
                    "sinfoni.std_star.pfx"));
    check_nomsg(pfx = cpl_parameter_get_int(p));

    cknull_nomsg(p = cpl_parameterlist_find(config,
                    "sinfoni.std_star.pfy"));
    check_nomsg(pfy = cpl_parameter_get_int(p));

    cknull(list_object = cpl_imagelist_new (),
           "could not allocate memory");

    /*
    sed = sinfo_extract_filename(sof, SINFO_CALIB_SED) ;
    stdstars = sinfo_extract_filename(sof, SINFO_CALIB_STDSTARS) ;
     */

    if (cfg->convInd == 1) {
        factor = sinfo_new_floatarray(cfg->nframes);
    }

    if(NULL != cpl_frameset_find(sof,PRO_COADD_STD)) {
        frame = cpl_frameset_find(sof,PRO_COADD_STD);
        strcpy(std_cub_filename,cpl_frame_get_filename(frame));
    } else if(NULL != cpl_frameset_find(sof,PRO_COADD_PSF)) {
        frame = cpl_frameset_find(sof,PRO_COADD_PSF);
        strcpy(std_cub_filename,cpl_frame_get_filename(frame));
    } else if(NULL != cpl_frameset_find(sof,PRO_COADD_OBJ)) {
        frame = cpl_frameset_find(sof,PRO_COADD_OBJ);
        strcpy(std_cub_filename,cpl_frame_get_filename(frame));
    } else if(NULL != cpl_frameset_find(sof,PRO_COADD_PUPIL)) {
        frame = cpl_frameset_find(sof,PRO_COADD_PUPIL);
        strcpy(std_cub_filename,cpl_frame_get_filename(frame));
    } else {
        sinfo_msg_error("Frame %s, %s, %s or %s not found! Exit!",
                        PRO_COADD_STD,PRO_COADD_PSF,
                        PRO_COADD_OBJ,PRO_COADD_PUPIL );
        goto cleanup;
    }

    cknull(plist = cpl_propertylist_load(std_cub_filename, 0),
           "getting header from reference ima frame %s",std_cub_filename);

    cenpix = sinfo_pfits_get_crpix3(plist);
    cenLambda = sinfo_pfits_get_crval3(plist);
    /* dispersion = sinfo_pfits_get_cdelt3(plist); */


    if (cpl_propertylist_has(plist, KEY_NAME_CDELT3)) {
        disp=cpl_propertylist_get_double(plist, KEY_NAME_CDELT3);
    } else {
        sinfo_msg_warning("Keyword %s not found.",KEY_NAME_CDELT3);
    }


    sinfo_free_propertylist(&plist) ;

    /* we find automatiocally extraction parameters */

    if(NULL != cpl_frameset_find(sof,PRO_MED_COADD_STD)) {
        frame = cpl_frameset_find(sof,PRO_MED_COADD_STD);
        strcpy(std_med_filename,cpl_frame_get_filename(frame));
        check_nomsg(std_med_ima=cpl_image_load(std_med_filename,
                        CPL_TYPE_FLOAT,0,0));
    } else if(NULL != cpl_frameset_find(sof,PRO_OBS_STD)) {
        check_nomsg(frame = cpl_frameset_find(sof,PRO_OBS_STD));
        strcpy(std_cub_filename,cpl_frame_get_filename(frame));
        check_nomsg(cube = cpl_imagelist_load(std_cub_filename,
                        CPL_TYPE_FLOAT,0));
        strcpy(std_med_filename,STDSTAR_OUT_MED_CUBE);
        check_nomsg(std_med_ima=cpl_imagelist_collapse_median_create(cube));
        sinfo_free_imagelist(&cube);

        ck0(sinfo_pro_save_ima(std_med_ima,ref_set,sof,STDSTAR_OUT_MED_CUBE,
                        PRO_MED_OBS_PSF,NULL,plugin_id,config),
            "Error saving image %s tag %s",STDSTAR_OUT_MED_CUBE,PRO_MED_OBS_PSF);

    } else if(NULL != cpl_frameset_find(sof,PRO_MED_COADD_PSF)) {
        check_nomsg(frame = cpl_frameset_find(sof,PRO_MED_COADD_PSF));
        strcpy(std_med_filename,cpl_frame_get_filename(frame));
        check_nomsg(std_med_ima=cpl_image_load(std_med_filename,
                        CPL_TYPE_FLOAT,0,0));
    } else if(NULL != cpl_frameset_find(sof,PRO_OBS_PSF)) {
        check_nomsg(frame = cpl_frameset_find(sof,PRO_OBS_PSF));
        strcpy(std_cub_filename,cpl_frame_get_filename(frame));
        check_nomsg(cube=cpl_imagelist_load(std_cub_filename,CPL_TYPE_FLOAT,0));
        strcpy(std_med_filename,STDSTAR_OUT_MED_CUBE);
        check_nomsg(std_med_ima=cpl_imagelist_collapse_median_create(cube));
        sinfo_free_imagelist(&cube);

        ck0(sinfo_pro_save_ima(std_med_ima,ref_set,sof,STDSTAR_OUT_MED_CUBE,
                        PRO_MED_OBS_PSF,NULL,plugin_id,config),
            "Error saving image %s tag %s",STDSTAR_OUT_MED_CUBE,PRO_MED_OBS_PSF);

    } else if(NULL != cpl_frameset_find(sof,PRO_MED_COADD_OBJ)) {
        check_nomsg(frame = cpl_frameset_find(sof,PRO_MED_COADD_OBJ));
        strcpy(std_med_filename,cpl_frame_get_filename(frame));
        check_nomsg(std_med_ima=cpl_image_load(std_med_filename,
                        CPL_TYPE_FLOAT,0,0));
    } else if(NULL != cpl_frameset_find(sof,PRO_OBS_OBJ)) {
        check_nomsg(frame = cpl_frameset_find(sof,PRO_OBS_OBJ));
        strcpy(std_cub_filename,cpl_frame_get_filename(frame));
        check_nomsg(cube = cpl_imagelist_load(std_cub_filename,
                        CPL_TYPE_FLOAT,0));
        strcpy(std_med_filename,STDSTAR_OUT_MED_CUBE);
        check_nomsg(std_med_ima=cpl_imagelist_collapse_median_create(cube));
        sinfo_free_imagelist(&cube);

        ck0(sinfo_pro_save_ima(std_med_ima,ref_set,sof,STDSTAR_OUT_MED_CUBE,
                        PRO_MED_OBS_OBJ,NULL,plugin_id,config),
            "Error saving image %s tag %s",STDSTAR_OUT_MED_CUBE,PRO_MED_OBS_OBJ);
    } else {
        sinfo_msg_error("Frame %s %s %s %s %s %s not found! Exit!",
                        PRO_MED_COADD_STD, PRO_OBS_STD,
                        PRO_MED_COADD_PSF, PRO_OBS_PSF,
                        PRO_MED_COADD_OBJ, PRO_OBS_OBJ);
        goto cleanup;
    }

    check_nomsg(std_med_dup=cpl_image_duplicate(std_med_ima));
    cpl_image_reject_value(std_med_dup,CPL_VALUE_NAN);
    sinfo_clean_nan(&std_med_dup);
    ima_szx=cpl_image_get_size_x(std_med_ima);
    ima_szy=cpl_image_get_size_y(std_med_ima);
    /* TODO: Here we remove 3 pixels at the image margin to prevent problems
     * with spikes at the image borders that could be more intense than the PSF
     * image peak. On the other side this does not prevent that other pixels
     * in the image are flagged. Better would be to flag any bad pixel/outlier
     * using HDRL.
     */
    //int margin=3;
    cpl_image_reject_value(std_med_dup,CPL_VALUE_NAN);

    double peak=0;
    double max_x;
    double max_y;
    sinfo_gaussian_maxpos(std_med_dup,5,&max_x,&max_y,&peak);
    max_ima_x=(int)(max_x+0.5);
    max_ima_y=(int)(max_y+0.5);

    /* This is not robust
    check_nomsg(cpl_image_get_maxpos_window(std_med_dup,
                    margin,margin,ima_szx-margin,ima_szy-margin,
                    &max_ima_x,&max_ima_y));
     */

    sinfo_free_image(&std_med_dup);



    wllx= ((max_ima_x-psf_sz)>0)       ? (max_ima_x-psf_sz) : 1;
    wlly= ((max_ima_y-psf_sz)>0)       ? (max_ima_y-psf_sz) : 1;
    wurx= ((max_ima_x+psf_sz)<ima_szx) ? (max_ima_x+psf_sz) : ima_szx ;
    wury= ((max_ima_y+psf_sz)<ima_szy) ? (max_ima_y+psf_sz) : ima_szy ;
    /*
    sinfo_msg("wllx=%d wlly=%d wurx=%d wury=%d\n",wllx,wlly,wurx,wury);
    cpl_image_get_maxpos_window(std_med_ima,wllx,wlly,wurx,wury,
                                &max_ima_x,&max_ima_y);
     */
    check_nomsg(qclog_tbl = sinfo_qclog_init());
    check_nomsg(max_ima_cx=cpl_image_get_centroid_x_window(std_med_ima,wllx,
                    wlly,wurx,wury));
    check_nomsg(max_ima_cy=cpl_image_get_centroid_y_window(std_med_ima,wllx,
                    wlly,wurx,wury));

    xshift=max_ima_cx-ima_szx/2;
    yshift=max_ima_cy-ima_szy/2;
    xshift=max_x-ima_szx/2;
    yshift=max_y-ima_szy/2;

    ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC SHIFTX",xshift,
                    "X shift centroid - center image","%f"));

    ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC SHIFTY",yshift,
                    "Y shift centroid - center image","%f"));

    if(
                    ((max_ima_x-psf_sz) < 1) ||
                    ((max_ima_y-psf_sz) < 1) ||
                    ((max_ima_x+psf_sz) > ima_szx) ||
                    ((max_ima_x+psf_sz) > ima_szy)
    )
    {
        psf_sz = (psf_sz < (max_ima_x-1))     ? psf_sz : (max_ima_x-1);
        psf_sz = (psf_sz < (max_ima_y-1))     ? psf_sz : (max_ima_y-1);
        psf_sz = (psf_sz < ima_szx-max_ima_x) ? psf_sz : (ima_szx-max_ima_x);
        psf_sz = (psf_sz < ima_szy-max_ima_y) ? psf_sz : (ima_szy-max_ima_y);
        //added to prevent seg fault by cpl_image_fit_gaussian
        psf_sz = (psf_sz > 4) ? psf_sz : 4;
    }

    ck0_nomsg(sinfo_qclog_add_int(qclog_tbl,"QC FWHM LLX",cfg->llx,
                    "STD star FWHM LLX","%d"));
    ck0_nomsg(sinfo_qclog_add_int(qclog_tbl,"QC FWHM LLY",cfg->lly,
                    "STD star FWHM LLY","%d"));
    ck0_nomsg(sinfo_qclog_add_int(qclog_tbl,"QC FWHM HBX",cfg->halfbox_x,
                    "STD star FWHM HBX","%d"));
    ck0_nomsg(sinfo_qclog_add_int(qclog_tbl,"QC FWHM HBX",cfg->halfbox_y,
                    "STD star FWHM HBY","%d"));


    /* call the 2D-Gaussian fit routine */
    for ( i = 0 ; i < 7 ; i++ )
    {
        mpar[i] = 1 ;
    }


    if(-1 == sinfo_new_fit_2d_gaussian(std_med_ima,
                    fpar,
                    dpar,
                    mpar,
                    cfg->llx,
                    cfg->lly,
                    cfg->halfbox_x,
                    cfg->halfbox_y,
                    &check4 ) ) {
        irplib_error_recover(clean_state,"2d Gaussian fit failed");
        /* return 0; */

    } else {

        ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC FWHM MAJ",fpar[4],
                        "STD star FWHM on major axis","%f"));
        ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC FWHM MIN",fpar[5],
                        "STD star FWHM on minor axis","%f"));
        ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC THETA",fpar[6],
                        "STD star ellipsis angle theta","%f"));


    }

    /*
    sinfo_msg("Gauss fit params: xc,yc,amp,bkg,fwhm_x,fwhm_y,angle\n");
    for ( i = 0 ; i < 7 ; i++ )
      {
        sinfo_msg("fpar[%d]=%f dpar[%d]=%f\n",i,fpar[i],i,dpar[i]);
      }
     */

    if(CPL_ERROR_NONE == cpl_image_fit_gaussian(std_med_ima,
                    max_ima_x,
                    max_ima_y,
                    psf_sz,
                    &norm,
                    &xcen,
                    &ycen,
                    &sig_x,
                    &sig_y,
                    &fwhm_x,
                    &fwhm_y)) {


        ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC FWHMX",fwhm_x,
                        "STD star FWHM on X","%f"));
        ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC FWHMY",fwhm_y,
                        "STD star FWHM on Y","%f"));

        cfg -> halfbox_x =  (floor)(0.5*(fwhm_x+fwhm_y)*cfg->fwhm_factor+0.5);

        cfg -> halfbox_y =  (floor)(0.5*(fwhm_x+fwhm_y)*cfg->fwhm_factor+0.5);

    } else {

        irplib_error_recover(clean_state,"Problem fitting Gaussian");
        cpl_error_reset();

    }

    /* we use a large value of kappa to be sure to flag well the object */
    cpl_mask* obj_mask;

    if(strcmp(extract_method,"optimal") != 0) {
        double kappa=5.;
        obj_mask=sinfo_object_mask(std_med_ima,pfm,pfx,pfy,kappa);
    }

    //sinfo_free_image(&std_med_ima);

    /*
      sinfo_msg("max ima=%d %d psf_sz=%d\n",max_ima_x,max_ima_y,psf_sz);
      sinfo_msg("centroid ima=%f %f\n",max_ima_cx,max_ima_cy);
      sinfo_msg("gauss=norm=%f xcen=%f ycen=%f sig_x=%f "
                "sig_y=%f fwhm_x=%f fwhm_y=%f\n",
                          norm,xcen,ycen,sig_x,sig_y,fwhm_x,fwhm_y);
     */

    cfg -> llx = (int)(xcen-cfg->halfbox_x);
    cfg -> llx = (cfg -> llx  > 0 ) ? cfg -> llx  : 1;

    if((cfg->llx+2*cfg->halfbox_x) >= ima_szx) {
        cfg -> halfbox_x=(int) ((ima_szx-cfg->llx-1)/2);
        check1++;
    }

    cfg -> lly = (int)(ycen-cfg->halfbox_y);
    cfg -> lly = (cfg -> lly  > 0 ) ? cfg -> lly  : 1;
    if((cfg->lly+2*cfg->halfbox_y) >= ima_szy) {
        cfg -> halfbox_y=(int) ((ima_szy-cfg->lly-1)/2);
        check1++;
    }
    ck0_nomsg(sinfo_qclog_add_int(qclog_tbl,"QC CHECK1",check1,
                    "Check on evaluation box","%d"));

    /*
      sinfo_msg("llx= %d lly= %d\n",cfg->llx, cfg->lly);
      sinfo_msg("halfbox_x=%d halfbox_y=%d\n",cfg->halfbox_x,cfg->halfbox_y);
     */

    /*
#----------------------------------------------------------------------
#---------------------------EXTRACTION---------------------------------
#----------------------------------------------------------------------
     */

    sinfo_msg("Extraction");
    cknull(spectrum = (cpl_image**) cpl_calloc (cfg -> nframes,
                    sizeof(cpl_image*)),
                    "Could not allocate memory for spectrum image");

    for (fra=0; fra < cfg->nframes; fra++) {
        name = cfg->inFrameList[fra];
        if(sinfo_is_fits_file(name) != 1) {
            sinfo_msg_error("Input file %s is not FITS",name);
            goto cleanup;
        }
        cknull(cube = cpl_imagelist_load(name,CPL_TYPE_FLOAT,0),
               "could not load data cube" );

        if (exptime == FLAG) {
            sinfo_msg_error("could not find exposure time in the fits header");
            return -1;
        }
        exptime = sinfo_pfits_get_ditndit(name);



        sinfo_msg("cfg->gain %f",cfg->gain);
        check_nomsg(tbl_spectrum=cpl_table_new(cpl_imagelist_get_size(cube)));

        if(strcmp(extract_method,"optimal") == 0) {
            sinfo_msg("optimal extraction");
            if(NULL==(spectrum[fra]=sinfo_new_optimal_extraction_from_cube( cube,
                            cfg->llx,
                            cfg->lly,
                            cfg->halfbox_x,
                            cfg->halfbox_y,
                            cfg->fwhm_factor,
                            BKG_VARIANCE,
                            SKY_FLUX,
                            cfg->gain,
                            exptime,
                            name,
                            &tbl_spectrum,
                            qc_info,
                            &check2))){

                irplib_error_recover(clean_state,
                                     "could not do sinfo_optimalExtractionFromCube");
            } else {
                check_nomsg(cpl_imagelist_set(list_object,
                                cpl_image_duplicate(spectrum[fra]), fra));

            }


        } else {
            sinfo_msg("simple extraction");
            if(NULL==(spectrum[fra]=sinfo_simple_extraction_from_cube(cube,obj_mask,
                            name,&tbl_spectrum,qc_info,&check2))){

                irplib_error_recover(clean_state,
                                "could not do sinfo_simpleExtractionFromCube");

            } else {

                check_nomsg(cpl_imagelist_set(list_object,
                                cpl_image_duplicate(spectrum[fra]), fra));
            }

        }
        cpl_mask_delete(obj_mask);


        ck0_nomsg(sinfo_qclog_add_int(qclog_tbl,"QC CHECK2",
                        check2,"Check on evaluation box","%d"));


        ck0(sinfo_pro_save_tbl(tbl_spectrum,ref_set,sof,
                        (char*)STDSTAR_OUT_TABLE,
                        PRO_STD_STAR_SPECTRA,qclog_tbl,
                        plugin_id,config),
            "cannot dump ima %s", "out_std_star_spectrum.fits");


        sinfo_free_table(&qclog_tbl);

        if (do_compute_eff!=0 && frm_std_cat !=NULL && frm_atmext != NULL) {
            sinfo_msg("compute efficiency");
            frm_sci     = cpl_frameset_find(sof,PRO_STD_STAR_SPECTRA);
            frm_std_cat = cpl_frameset_find(sof,FLUX_STD_CATALOG);
            frm_atmext  = cpl_frameset_find(sof,EXTCOEFF_TABLE);



            check_nomsg(tot_eff=sinfo_efficiency_compute(frm_sci,frm_std_cat,
                            frm_atmext));
            ck0(sinfo_pro_save_tbl(tot_eff,ref_set,sof,(char*)EFFICIENCY_FILENAME,
                            PRO_EFFICIENCY,qclog_tbl,plugin_id,config),
                "cannot dump ima %s", "out_.fits");
        }

        /*
         if(spectrum[fra] != NULL ) {
         sinfo_free_image(&(spectrum)[fra]);
         }
         */
        /*----determine the intensity conversion factor if wished--------*/
        if (cfg->convInd == 1) {
            sinfo_msg("Determines convertion factor");

            convfactor = sinfo_new_determine_conversion_factor( cube,
                            cfg->mag,
                            exptime,
                            cfg->llx,
                            cfg->lly,
                            cfg->halfbox_x,
                            cfg->halfbox_y,
                            &check3 );


            if (convfactor < -100000.) {
                sinfo_msg_warning("could not do sinfo_determineConversionFactor!" );
                /* goto cleanup; */
            } else {
                sinfo_new_array_set_value(factor, convfactor, fra);
            }
        }
        sinfo_free_imagelist(&cube);
    } /* end loop over fra */

    sinfo_free_table(&tbl_spectrum);
    sinfo_free_image_array(&spectrum,cfg->nframes);
    if (cfg->convInd == 1) {
        sinfo_msg("Determines clean factor");
        cleanfactor = sinfo_new_clean_mean(factor,
                        cfg->nframes,
                        cfg->lo_reject*100.,
                        cfg->hi_reject*100.);
    }
    if (cleanfactor > 100000. || cleanfactor == FLAG) {
        sinfo_msg_error("could not do sinfo_clean_mean!" );
        goto cleanup;
    }

    /*---read the fits header to change the gain and noise parameter-----*/
    sinfo_msg("Average with rejection");

    no=cpl_imagelist_get_size(list_object);
    lo_cut=(floor)(cfg->lo_reject*no+0.5);
    hi_cut=(floor)(cfg->hi_reject*no+0.5);
    if(no > 0) {
        cknull(img_spct=cpl_imagelist_collapse_minmax_create(list_object,
                        lo_cut,hi_cut),
                        "sinfo_average_with_rejection failed" );
    }

    sinfo_free_imagelist(&list_object);

    if(no > 0) {
        check_nomsg(qclog_tbl = sinfo_qclog_init());

        ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC CONVFCT",cleanfactor,
                        "Conversion factor","%g"));
        ck0_nomsg(sinfo_qclog_add_int(qclog_tbl,"QC CHECK3",check3,
                        "Check evaluation box","%d"));
        ck0(sinfo_pro_save_ima(img_spct,ref_set,sof,cfg->outName,
                        PRO_STD_STAR_SPECTRUM,qclog_tbl,
                        plugin_id,config),
            "cannot dump ima %s", cfg->outName);

        sinfo_new_set_wcs_spectrum(img_spct,cfg->outName,cenLambda,disp,cenpix);
        sinfo_free_table(&qclog_tbl);
    }
    /*#---free memory---*/
    if(factor != NULL) sinfo_new_destroy_array(&factor);
    sinfo_free_image(&img_spct);
    sinfo_free_image(&std_med_ima);
    sinfo_stdstar_free(&cfg);
    sinfo_free_frameset(&raw);

    return 0;

    cleanup:

    sinfo_free_table(&tbl_spectrum);
    sinfo_free_table(&qclog_tbl);
    sinfo_free_imagelist(&list_object);
    if(spectrum != NULL) sinfo_free_image_array(&spectrum,cfg->nframes);
    sinfo_free_image(&std_med_ima);
    sinfo_free_image(&std_med_dup);
    sinfo_free_imagelist(&cube);
    sinfo_free_propertylist(&plist) ;
    if(factor != NULL) sinfo_new_destroy_array(&factor);
    sinfo_free_image(&img_spct);
    sinfo_stdstar_free (&cfg);
    sinfo_free_frameset(&raw);
    return -1;

}


/**@}*/
