/*
 * This file is part of the ESO SINFONI Pipeline
 * Copyright (C) 2004,2005 European Southern Observatory
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
 */
/*----------------------------------------------------------------------------

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

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


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

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


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

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

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

  double dis=0 ;
  double cwav=0 ;

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


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

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

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

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

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


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

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

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


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

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

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


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


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

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


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

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

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



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

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


      for(i=1;i<nx-1;i++) {
	for(j=1;j<ny-1;j++) {
	  if(!isnan(pd[nx*j+i])) {
	    pd[nx*j+i]=2.0*dis/(pw[nx*(j+1)+i]-pw[nx*(j-1)+i]);
	  }
	}
	if(!isnan(pd[i])) {
	  pd[i]=dis/(pw[nx+i]-pw[i]);
	}
	if(!isnan(pd[nx*(ny-1)+i])) {
	  pd[nx*(ny-1)+i]=dis/(pw[nx*(ny-1)+i]-pw[nx*(ny-2)+i]);
	}
      }


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



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



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





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

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


      sinfo_free_image(&wim);

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


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

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

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



      }


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


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


	}

      }

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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



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

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

	  sinfo_free_imagelist(&csky) ;

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

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



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

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

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

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

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

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

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

	    sinfo_free_image(&eima_avg);

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

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

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

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

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

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

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

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

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

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

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

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

		sinfo_skycor_qc_delete(&sqc);

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

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

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

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

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


  return 0;

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

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

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

  return -1;



}

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

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


	return;
}

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

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

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

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

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

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

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

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


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



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

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

  sinfo_free_image(&dif);


  return out;

}
*/
/**@}*/
