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

/*----------------------------------------------------------------------------
                                Includes
 ---------------------------------------------------------------------------*/
#include "sinfo_new_objnod.h"
#include "sinfo_hidden.h"
#include "sinfo_pro_save.h"
#include "sinfo_objnod_ini_by_cpl.h"
#include "sinfo_functions.h"
#include "sinfo_pfits.h"
#include "sinfo_utilities_scired.h" 
#include "sinfo_wave_calibration.h"
#include "sinfo_cube_construct.h"
#include "sinfo_error.h"
#include "sinfo_utils_wrappers.h"

/*----------------------------------------------------------------------------
                                Defines
 ---------------------------------------------------------------------------*/
#define PI_NUMB        (3.1415926535897932384626433832795) /* pi */


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

/**@{*/
/**
 * @addtogroup sinfo_rec_jitter Cube construction and coaddition
 *
 * TBD
 */


/*----------------------------------------------------------------------------
   Function     : sinfo_new_objnod()
   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_objnod (const char* plugin_id,cpl_parameterlist* config, 
            cpl_frameset* sof, const char* procatg)
{

    object_config * cfg=NULL ;
    cpl_image * im=NULL ;
    cpl_image * wavemapim=NULL ;
    cpl_image * resampledImage=NULL ;
    cpl_image * calim=NULL ;
    cpl_image * halospec=NULL ;
    cpl_image * sky_im=NULL;
    cpl_image* res_flat=NULL;
    cpl_image* res_sky=NULL;
    cpl_image* flat_im=NULL;
    cpl_image* jitter_image=NULL;
    cpl_image* eima_avg=NULL;
    cpl_image* eima_med=NULL;
    cpl_imagelist  * cube=NULL ;
    cpl_imagelist  * outcube=NULL ;
    cpl_imagelist  * outcube2=NULL ;
    cpl_imagelist  ** cubeobject=NULL ;
    cpl_imagelist  ** cube_tmp=NULL ;
    cpl_imagelist  * jittercube=NULL ;
    cpl_imagelist  * maskcube=NULL ;
    cpl_imagelist* cflat=NULL;
    cpl_imagelist* cflat2=NULL;
    cpl_imagelist* csky=NULL;
    cpl_imagelist* csky2=NULL;


    int i=0;
    int n=0;
    int partind = 0 ;
    int centralpix=0 ;
    int z_siz=0;
    int z_min=0;
    int z_max=0;
    int z=0;
    int z_stp=100;
    int scales_sky=0;
    int ks_clip=0;
    double kappa=2.0;

    float ref_offx=0;
    float ref_offy=0;
    float mi=0 ;
    float ma=0 ;
    float fcol=0 ;
    float center_x=0;
    float newcenter_x=0 ;
    float center_y=0;
    float newcenter_y=0;
    float cd1_1=0;
    float cd1_2=0;
    float cd2_1=0;
    float cd2_2=0;
    float pixelscale=0;
    float angle=0;
    float radangle=0;
    double exptime=0;

    float *  correct_dist=NULL ;
    float * distances=NULL ;
    double * times=NULL ;
    float * offsetx=NULL;
    float * offsety=NULL;
    float ** slit_edges=NULL ;
    float offx_min=1.e10;
    float offy_min=1.e10;
    float offx_max=-1.e10;
    float offy_max=-1.e10;

    double dis=0;
    double centralLambda=0;

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


    char * name=NULL ;
    char * partname=NULL;
    char * partname2=NULL;
    char file_name[MAX_NAME_SIZE];
    int vllx=0;
    int vlly=0;
    int vurx=0;
    int vury=0;

    int onp=0;
    int j=0;
    cpl_image* j_img=NULL;
    cpl_image* m_img=NULL;
    cpl_table* qclog_tbl=NULL;
    cpl_image* ill_cor=NULL;
    cpl_frame* frame=NULL;
    cpl_frameset* stk=NULL;
    cpl_parameter* p=NULL;
    cpl_propertylist* plist=NULL;
    int mosaic_max_size=0;

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

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

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


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

    cknull(cfg = sinfo_parse_cpl_input_objnod(config,sof,&stk),
       "Error setting parameter configuration");
 
    ck0(sinfo_check_input_data(cfg),"error checking input");

    if ( cfg->jitterind == 1 )
    {
        cknull(times = (double*) cpl_calloc (cfg->nframes, sizeof (double)), 
           " could not allocate memory!") ;
 
        cknull(offsetx = (float*) cpl_calloc (cfg->nframes, sizeof(float)),
           " could not allocate memory!") ;

        cknull(offsety = (float*) cpl_calloc (cfg->nframes, sizeof(float)),
           " could not allocate memory!") ;
    }
  
    if (cfg->jitterind == 0)
    {
        if ( NULL != (partname = strtok(cfg->outName, "."))) 
        {
            partname2 = strtok (NULL, ".") ;
            partind = 1 ;
        }
    }

    ck0(sinfo_auto_size_cube5(cfg,&ref_offx,&ref_offy,
                                &offx_min,&offy_min,
                                &offx_max,&offy_max),
                             "Error resizing cube");
  


    check_nomsg(p=cpl_parameterlist_find(config,"sinfoni.objnod.fcol"));
    check_nomsg(fcol=cpl_parameter_get_double(p));
   
    if(NULL != cpl_frameset_find(sof,PRO_ILL_COR)) {
     sinfo_msg("Illumination correction cube is provided");
     frame = cpl_frameset_find(sof,PRO_ILL_COR);
     ill_cor=cpl_image_load(cpl_frame_get_filename(frame),CPL_TYPE_FLOAT,0,0);
    } else {
     sinfo_msg("Illumination correction cube not provided");
     cpl_error_reset();
    }

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

        sinfo_msg("Read FITS information");
        name = cfg->framelist[n] ;    
        if (n == 0)
    {
        strcpy (name_jitter, name) ;
    }   
        if( sinfo_is_fits_file(name) != 1) {
          sinfo_msg_error("Input file %s is not FITS",name);
          goto cleanup;
    }
    
    /* get some header values and compute the CD-sinfo_matrix */
        plist=cpl_propertylist_load(name,0);
    pixelscale = sinfo_pfits_get_pixscale(plist) /2;
    angle = sinfo_pfits_get_posangle(plist) ;
        /* in PUPIL data there is not posangle info: we reset the error */
        if(cpl_error_get_code() != CPL_ERROR_NONE) {
      cpl_error_reset();
        }
    sinfo_free_propertylist(&plist);
    radangle = angle * PI_NUMB / 180. ;
    cd1_1 = cos(radangle) ;
    cd1_2 = sin(radangle) ;
    cd2_1 = -sin(radangle) ;
    cd2_2 = cos(radangle) ;
    
    sinfo_msg("frame no.: %d, name: %s\n", n, name) ;
    cknull(im = cpl_image_load(name,CPL_TYPE_FLOAT,0,0),
           " could not load frame %s!",name) ;

    if (cfg->jitterind == 1)
    {
      exptime = sinfo_pfits_get_ditndit(name) ;

      if (exptime == FLAG)
        {
          sinfo_msg_error("could not read fits header keyword exptime!");
          goto cleanup;
        }
      times[n] = exptime ;
          ck0(sinfo_new_assign_offset(n,name,offsetx,offsety,
                                      ref_offx,ref_offy),
                                      "Error assigning offsets");

    }

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

        cknull(resampledImage = sinfo_new_defined_resampling( im, 
                                  wavemapim, 
                                  cfg->ncoeffs,
                                  &cfg->nrows,
                                  &dis,
                                  &mi,
                                  &ma,
                                  &centralLambda,
                                  &centralpix),
           " sinfo_definedResampling() failed" ) ;

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

            sinfo_free_image(&flat_im) ;
      }
     
      if(strcmp(cfg->sky_dist,"no_sky")!=0) {
        sinfo_msg("Resampling sky");
        check_nomsg(sky_im=cpl_image_load(cfg->sky_dist,
                                              CPL_TYPE_FLOAT,0,0));
        cknull(res_sky = sinfo_new_defined_resampling(sky_im,
                              wavemapim,
                              cfg->ncoeffs,
                              &cfg->nrows,
                              &dis,
                              &mi,
                              &ma,
                              &centralLambda,
                              &centralpix),
           " sinfo_definedResampling() failed" );

        sinfo_free_image(&sky_im) ;

       
      }
    }

        sinfo_msg ("dispersion %f\n", dis) ;
        sinfo_msg ("lambda min %f max %f cent %f\n", mi,ma,centralLambda ) ;
        sinfo_msg ("central pixel %d\n", centralpix) ; 

        sinfo_free_image(&im) ;
        sinfo_free_image(&wavemapim) ;

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

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

      sinfo_free_image(&halospec) ;
      sinfo_free_image(&resampledImage) ;
      resampledImage = cpl_image_duplicate(calim) ;
      sinfo_free_image(&calim);
        }
    
        /*
         *-------------------------------------------------------------------
         *------------------CUBECREATION-------------------------------------
         *-------------------------------------------------------------------
     */
    sinfo_msg("Cube creation");
    /*---select north-south-test or fitting of slitlet edges--*/
    if (cfg->northsouthInd == 0) {
      sinfo_msg("cfg->northsouthInd == 0");
      cknull(slit_edges = sinfo_read_slitlets_edges(cfg->nslits,cfg->poslist),
         "error reading slitlets edges");
    } else {
      sinfo_msg("cfg->northsouthInd != 0");
      cknull(distances = sinfo_read_distances(cfg->nslits,cfg->distlist),
         "error reading distances");
    }
 
    cknull(correct_dist = (float*) cpl_calloc(cfg->nslits, sizeof (float)),
           " could not allocate memory!") ;

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

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

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

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

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


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

        /*
         *--------------------------------------------------------------------
         *------------------------FINETUNING----------------------------------
         *--------------------------------------------------------------------
         * shift the rows of the reconstructed images of the data cube to the 
         * correct sub pixel position select the shift method: polynomial 
         * interpolation, FFT or cubic spline interpolation
         *--------------------------------------------------------------------
         */
 
    if(n==0) {
      if(strcmp(cfg->sky_dist,"no_sky")!=0) {
         cknull(csky2=sinfo_new_fine_tune(csky,
                                             correct_dist,
                                             cfg->method,
                                             cfg->order,
                          cfg->nslits),
            " could not fine tune the data cube") ;

         sinfo_free_imagelist(&csky);
         sinfo_msg("Stretch output cube along Y direction");
 
         cknull(csky = sinfo_new_bin_cube(csky2,1,2,0,63,0,63),
            "error rebinning sky cube");
         sinfo_free_imagelist(&csky2);

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

            sinfo_new_set_wcs_cube(csky, "out_sky_cube.fits", centralLambda, 
                          dis, centralpix, center_x, center_y);

         sinfo_free_imagelist(&csky) ;

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

            sinfo_new_set_wcs_image(eima_med,"out_sky_med.fits", 
                                     center_x, center_y);
         sinfo_free_image(&eima_med);
      }


      if(strcmp(cfg->mflat_dist,"not_found")!=0) {

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

        sinfo_free_imagelist(&cflat);
        sinfo_msg("Stretch output cube along Y direction");
 
        cknull(cflat = sinfo_new_bin_cube(cflat2,1,2,0,63,0,63),
           "Error binning flat cube");
        sinfo_free_imagelist(&cflat2);

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

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

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

        sinfo_free_image(&eima_avg);

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

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

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

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

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


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

    sinfo_new_set_wcs_cube(outcube, file_name, centralLambda, dis, 
                     centralpix, center_x, center_y);

       /* free memory */
        /* to prevent error message comment next line */
        sinfo_free_imagelist(&outcube2);
        sinfo_free_imagelist(&outcube) ;
    sinfo_free_float(&correct_dist) ;


    } /* end loop over n (nframes) */
 
    /* leak free */
    if(cfg->jitterind == 0) {
      goto exit;
    }   
     
    /* Here in case of autojitter we estimate the sky */
    if( (cfg->size_x*cfg->size_y*cfg->nframes) > (100*mosaic_max_size) ) {
      sinfo_msg_warning("Coadd cube size:%d,%d. N frames: %d",
                           cfg->size_x,cfg->size_y,cfg->nframes);
      sinfo_msg_warning("Max allowed should be such that "
                        "sixeX*sixeY*Nframes < 100*%d",mosaic_max_size);
      goto exit;
    } 
 
    if ( cfg->jitterind == 1 )
    {  
        check_nomsg(p = cpl_parameterlist_find(config, "sinfoni.objnod.vllx"));
        check_nomsg(vllx = cpl_parameter_get_int(p));
        check_nomsg(p = cpl_parameterlist_find(config, "sinfoni.objnod.vlly"));
        check_nomsg(vlly = cpl_parameter_get_int(p));
        check_nomsg(p = cpl_parameterlist_find(config, "sinfoni.objnod.vurx"));
        check_nomsg(vurx = cpl_parameter_get_int(p));
        check_nomsg(p = cpl_parameterlist_find(config, "sinfoni.objnod.vury"));
        check_nomsg(vury = cpl_parameter_get_int(p));
 
        cknull(cube_tmp =(cpl_imagelist**) cpl_calloc(cfg->nframes, 
                                                      sizeof (cpl_imagelist*)),
                                     "Could not allocate memory for cube_tmp");
        cknull(cubeobject =(cpl_imagelist**) cpl_calloc(cfg->nframes, 
                                                        sizeof(cpl_imagelist*)),
                                    "Could not allocate memory for cubeobject");

    for ( n = 0 ; n < cfg->nframes ; n++ ) {
          snprintf(file_name,MAX_NAME_SIZE-1,"%s%2.2d%s","out_cube_obj",
                     n,".fits");
      check_nomsg(cube_tmp[n] = cpl_imagelist_load(file_name,
                               CPL_TYPE_FLOAT,0));
      check_nomsg(cubeobject[n] = sinfo_new_cube_getvig(cube_tmp[n],
                                1+vllx,1+vlly,
                                64-vurx,64-vury));
          check_nomsg(sinfo_free_imagelist(&cube_tmp[n]));
    }
        sinfo_free_array_imagelist(&cube_tmp);

    }

    /*
        ---------------------------------------------------------------------
        ------------------------JITTERING------------------------------------
        ---------------------------------------------------------------------
    */

    if (cfg->jitterind == 1)
    {
    sinfo_msg("Jittering...");

        sinfo_msg("Coadded cube size. x: %d y: %d",
             cfg->size_x,cfg->size_y);
        check_nomsg(jittercube = cpl_imagelist_new()) ;


    /* 
        ---------------------------------------------------------------------
        -------------------THOMAS ALGORITHM----------------------------------
        ---------------------------------------------------------------------
    */
       
        check_nomsg(p=cpl_parameterlist_find(config,
                                             "sinfoni.objnod.scales_sky"));
        check_nomsg(scales_sky=cpl_parameter_get_bool(p));
        check_nomsg(p=cpl_parameterlist_find(config,"sinfoni.objnod.ks_clip"));
        check_nomsg(ks_clip = cpl_parameter_get_bool(p));
        check_nomsg(p=cpl_parameterlist_find(config,"sinfoni.objnod.kappa"));
        check_nomsg(kappa = cpl_parameter_get_double(p));


    if(scales_sky == 1) {
      sinfo_msg("Subtract spatial sinfo_median to each cube plane");
      for(n=0;n<cfg->nframes;n++) {
        sinfo_msg("process cube %d\n",n);
        sinfo_new_sinfoni_correct_median_it(&(cubeobject[n]));
      }
    }


        /* AMO CHECK */

        cknull(maskcube=cpl_imagelist_new(),"could not allocate cube!");
        
    /* Illumination correction */ 
        if(ill_cor != NULL) {
      for(n=0;n<cfg->nframes;n++) {
        sinfo_msg("Illumination correction is applied");
        cpl_imagelist_divide_image(cubeobject[n],ill_cor);
      }
    }
        sinfo_free_image(&ill_cor);
    
    sinfo_msg("Combine jittered cubes");


    if(ks_clip == 1) {
      sinfo_msg("Cube coaddition with kappa-sigma");
    }
        check_nomsg(onp=cpl_imagelist_get_size(cubeobject[0]));
    for(z=0;z<onp;z+=z_stp) {
      z_siz=(z_stp < (onp-z)) ? z_stp : (onp-z);
      z_min=z;
      z_max=z_min+z_siz;
      sinfo_msg("Coadding cubes: range [%4.4d,%4.4d) of 0-%d\n",
                           z_min,z_max,onp);

      for(j=z_min;j<z_max;j++) {
            check_nomsg(j_img=cpl_image_new(cfg->size_x,
                                            cfg->size_y,CPL_TYPE_FLOAT));
        check_nomsg(cpl_imagelist_set(jittercube,j_img,j));
            check_nomsg(m_img = cpl_image_new(cfg->size_x,
                                              cfg->size_y,CPL_TYPE_FLOAT));
            check_nomsg(cpl_imagelist_set(maskcube,m_img,j));
      }
      if(ks_clip == 1) {
        sinfo_new_combine_jittered_cubes_thomas_range(cubeobject,
                            jittercube,
                            maskcube,
                            cfg->nframes,
                            offsetx,offsety,
                            times,
                            cfg->kernel_type,
                            z_min,
                            z_max,
                            kappa);

      } else {
        sinfo_new_combine_jittered_cubes_range(cubeobject, 
                                             jittercube,
                                             maskcube,
                         cfg->nframes,
                                             offsetx,
                         offsety, 
                                             times,
                         cfg->kernel_type,
                                             z_min,
                                             z_max) ;
      }
    }
        sinfo_new_convert_0_to_ZERO_for_cubes(jittercube) ; 

      if (jittercube == NULL)
    {
        sinfo_msg_error(" could not allocate new data cube!") ;
        goto cleanup;
    }

        if (maskcube == NULL)
    {
        sinfo_msg_error(" could not merge the jittered data cubes\n") ;
            goto cleanup;
    }

    for ( i = 0 ; i <cfg->nframes  ; i++ ) {
      sinfo_free_imagelist(&cubeobject[i]);
    }
    sinfo_free_array_imagelist(&cubeobject);

        newcenter_x = cfg->size_x / 2. + 0.5 ;
    newcenter_y = cfg->size_y / 2. + 0.5 ;

        ck0(sinfo_pro_save_ims(jittercube,sof,sof,cfg->outName,
                   procatg,NULL,plugin_id,config),
        "cannot save cube %s", cfg->outName);

      sinfo_new_set_wcs_cube(jittercube, cfg->outName, centralLambda, 
                               dis, centralpix, center_x, center_y);

        cknull(jitter_image = sinfo_new_median_cube(jittercube),
               " could not do sinfo_medianCube()");


        ck0(sinfo_pro_save_ima(jitter_image,sof,sof,cfg->med_cube_name,
                   pro_med,NULL,plugin_id,config),
        "cannot save ima %s", cfg->outName);

      sinfo_new_set_wcs_image(jitter_image, cfg->med_cube_name,
                                center_x,center_y);

        sinfo_free_image(&jitter_image);

        ck0(sinfo_pro_save_ims(maskcube,sof,sof,cfg->maskname,
                   pro_mjit,NULL,plugin_id,config),
        "cannot save cube %s", cfg->maskname);

     sinfo_new_set_wcs_cube(maskcube, cfg->maskname, centralLambda, 
                               dis, centralpix, center_x, center_y);

        sinfo_free_double(&times) ;
        sinfo_free_float(&offsetx) ;
        sinfo_free_float(&offsety) ;
        sinfo_free_imagelist(&maskcube) ;
        sinfo_free_imagelist(&jittercube) ;         

    } /* end of jittering */

 exit:

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

 cleanup:
    sinfo_free_propertylist(&plist);
    sinfo_free_image(&jitter_image);
    sinfo_free_imagelist(&jittercube) ;
    sinfo_free_imagelist(&maskcube) ;

    if(cfg != NULL) {
      if(cube_tmp != NULL) {
    for ( n = 0 ; n < cfg->nframes ; n++ ) {
      sinfo_free_imagelist(&(cube_tmp[n]));
    }
        sinfo_free_array_imagelist(&cube_tmp);
      }
      if(cubeobject != NULL) {
    for ( n = 0 ; n < cfg->nframes ; n++ ) {
      sinfo_free_imagelist(&(cubeobject[n]));
    }
        sinfo_free_array_imagelist(&cubeobject);
      }

    }

    sinfo_free_imagelist(&outcube2) ;
    sinfo_free_imagelist(&outcube) ;
    sinfo_free_table(&qclog_tbl);
    sinfo_free_image(&eima_avg);
    sinfo_free_image(&eima_med);
    sinfo_free_imagelist(&cflat) ;
    sinfo_free_imagelist(&cflat2) ;
    sinfo_free_imagelist(&cube) ;
    sinfo_free_imagelist(&csky) ;
    sinfo_free_imagelist(&csky2) ;

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

    sinfo_free_float(&correct_dist);
    sinfo_free_image(&res_flat);
    sinfo_free_image(&res_sky);
    sinfo_free_image(&calim);
    sinfo_free_image(&halospec) ;
    sinfo_free_image(&sky_im) ;
    sinfo_free_image(&resampledImage);
    sinfo_free_image(&flat_im) ;
    sinfo_free_image(&wavemapim);
    sinfo_free_image(&im);
    sinfo_free_image(&ill_cor);
    sinfo_free_float(&offsety);
    sinfo_free_float(&offsetx);
    sinfo_free_double(&times);
    sinfo_objnod_free(&cfg);
    sinfo_free_frameset(&stk);

    return -1;   



}
/**@}*/
