/*                                                                            *
 *   This file is part of the ESO X-shooter Pipeline                          *
 *   Copyright (C) 2006 European Southern Observatory                         *
 *                                                                            *
 *   This library 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     *
 *                                                                            */

/*
 * $Author: amodigli $
 * $Date: 2013-08-16 08:25:29 $
 * $Revision: 1.97 $
 *
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/*----------------------------------------------------------------------------
                                 Includes
 ----------------------------------------------------------------------------*/
#include <xsh_utils_scired_slit.h>
#include <xsh_dfs.h>
#include <xsh_utils.h>
#include <xsh_utils_table.h>
#include <xsh_utils_efficiency.h>
#include <xsh_data_spectrum.h>
#include <xsh_model_utils.h>
#include <xsh_error.h>
#include <xsh_drl_check.h>
#include <xsh_pfits.h>
#include <xsh_hdrl_functions.h>
/*
static int 
xsh_frame_has_same_nod_pos(cpl_frame* ref, cpl_frame* cmp)
{
  int result=0;

  cpl_propertylist* href=NULL;
  cpl_propertylist* hcmp=NULL;

  const char* name_ref=NULL;
  const char* name_cmp=NULL;

  double ref_yoff=0;
  double ref_ra=0;
  double ref_dec=0;

  double cmp_yoff=0;
  double cmp_ra=0;
  double cmp_dec=0;

  name_ref=cpl_frame_get_filename(ref);
  name_cmp=cpl_frame_get_filename(cmp);
  href=cpl_propertylist_load(name_ref,0);
  hcmp=cpl_propertylist_load(name_cmp,0);

  if(cpl_propertylist_has(href, XSH_NOD_CUMULATIVE_OFFSETY)){

     check(ref_yoff=xsh_pfits_get_cumoffsety(href));
     check(cmp_yoff=xsh_pfits_get_cumoffsety(hcmp));

   if(ref_yoff==cmp_yoff) {
     result=1;
   } 

  } else {

     check(ref_ra=xsh_pfits_get_ra_cumoffset(href));
     check(ref_dec=xsh_pfits_get_dec_cumoffset(href));

     check(cmp_ra=xsh_pfits_get_ra_cumoffset(hcmp));
     check(cmp_dec=xsh_pfits_get_dec_cumoffset(hcmp));

    if((ref_ra==cmp_ra) && (ref_ra==cmp_ra)) {
     result=1;
    } 

  }
  cleanup:
  xsh_free_propertylist(&href);
  xsh_free_propertylist(&hcmp);

  return result;

}
*/

/**@{*/




/*--------------------------------------------------------------------------*/
/**
  @brief  Corrects parameters for binning
  @param    raws   the frames list
  @param    backg parameters controlling inter-order background correction
  @param    opt_extract_par parameters controlling optimal extraction
  @param    sub_sky_nbkpts1 sky background sampling points 1st iteration
  @param    sub_sky_nbkpts2 sky background sampling points 2nd iteration

  In case of failure the cpl_error_code is set.
 */
/*--------------------------------------------------------------------------*/

cpl_error_code 
xsh_stare_params_bin_scale(cpl_frameset* raws,
                     xsh_background_param* backg,
                     xsh_opt_extract_param *opt_extract_par,
                     int* sub_sky_nbkpts1,
                     int* sub_sky_nbkpts2)
{

  cpl_frame* frame=NULL;
  const char* name=NULL;
  cpl_propertylist *plist=NULL;
  int binx=0;
  int biny=0;

  check(frame=cpl_frameset_get_frame(raws,0));
  check(name=cpl_frame_get_filename(frame));
  check(plist=cpl_propertylist_load(name,0));
  check(binx=xsh_pfits_get_binx(plist));
  check(biny=xsh_pfits_get_biny(plist));
  xsh_free_propertylist( &plist);

  if(biny>1) {

    /* backg->sampley=backg->sampley/biny;
    number of points of the grid in y direction.
    Not to be bin dependent
    */

    backg->radius_y=backg->radius_y/biny;

    /* bin dependent */
    *sub_sky_nbkpts1*=0.75*biny;
    *sub_sky_nbkpts2*=0.75*biny;


    /*
    if(backg->smooth_y>0) {
      backg->smooth_y=backg->smooth_y/biny;
    }
    Smoothing radius' half size in x direction.
    For the moment not bin dependent, but for optimal results probably yes
    */
    /*
    rectify_par->rectif_radius=rectify_par->rectif_radius/biny;
    Rectify Interpolation radius
    For the moment not bin dependent, but for optimal results probably yes
    */

    /*
    rectify_par->rectif_bin_lambda=rectify_par->rectif_bin_lambda/biny;
    Rectify Wavelength Step
    For the moment not bin dependent, but for optimal results probably yes
    */

    /*
    loc_obj_par->loc_chunk_nb=loc_obj_par->loc_chunk_nb/biny;
    Localization Nb of chunks
    Not bin dependent
    */

    /*
    opt_extract_par->chunk_size=opt_extract_par->chunk_size/biny;
    Chunk size.
    */

    /*
    opt_extract_par->lambda_step=opt_extract_par->lambda_step/biny;
    Lambda step.
    For the moment not bin dependent, but for optimal results probably yes
    */


  }


  if(binx>1) {

    backg->radius_x=backg->radius_x/binx;

    /*
    if(backg->smooth_x>0) {
      backg->smooth_x=backg->smooth_x/binx;
    }
    Smoothing radius' half size in x direction
    For the moment not bin dependent, but for optimal results probably yes
    */

    /*
    rectify_par->rectif_bin_space=rectify_par->rectif_bin_space/binx;
    Rectify Position Step
    For the moment not bin dependent, but for optimal results probably yes
    */

    /*
    loc_obj_par->nod_step=loc_obj_par->nod_step/binx;
    Step (arcsec) between A and B images in nodding mode
    Not bin dependent
    */

    opt_extract_par->box_hsize=opt_extract_par->box_hsize/binx;

  }
 
 cleanup:
  xsh_free_propertylist(&plist);
  return cpl_error_get_code();

}


cpl_frameset* xsh_nod_group_by_reloff( cpl_frameset *ord_set,xsh_instrument *instrument, xsh_stack_param* stack_par)
{

  cpl_frameset *result = NULL;
  cpl_frameset *rmcrh_set = NULL;
  const cpl_frame *frame = NULL;
  cpl_propertylist *header = NULL;

  const char* nod_name = NULL;

  double rel_ra=0;
  double rel_dec=0;
  double A_cum_ra=0;
  double A_cum_dec=0;
  int A_number=1, B_number =1;
  int nod_number;
  char ftag[40];
  char name[40];

  cpl_frame *crhm_frame = NULL;

  XSH_ASSURE_NOT_NULL( ord_set);
  XSH_ASSURE_NOT_NULL( instrument);
  XSH_ASSURE_NOT_NULL( stack_par);

  check( result=cpl_frameset_new());

  cpl_frameset_iterator* it = cpl_frameset_iterator_new(ord_set);
  frame = cpl_frameset_iterator_get(it);

  check( nod_name = cpl_frame_get_filename( frame));  
  check( header = cpl_propertylist_load( nod_name, 0));

  check( A_cum_ra = xsh_pfits_get_ra_cumoffset( header));
  check( A_cum_dec = xsh_pfits_get_dec_cumoffset( header));

  xsh_free_propertylist( &header);
  /* loops over the input frames and identifies all
   * nod positions (having different value of RA-cumoff and/or DEC-cumoff
   * Frames at same nod position are combined to improve statistics
   * In this way a sequence like:
   * AAA BBB BBB AAA AAA BBBBB BBBBB AAAAAA is (median or sigma-clipped mean) combined in
   * A    B   B   A   A   B     B     A
   * And then one can build usual pairs A-B B-A and apply the usual [(A-B) - shifted(B-A)]
   * nod algorithm
   * */
  while( frame != NULL){
    double cum_ra=0;
    double cum_dec=0;
    double nrel_ra, nrel_dec;
    const char *type= NULL;

    check( nod_name = cpl_frame_get_filename( frame));
    check( header = cpl_propertylist_load( nod_name, 0));
    check( cum_ra = xsh_pfits_get_ra_cumoffset( header));
    check( cum_dec = xsh_pfits_get_dec_cumoffset( header));    
    check( rel_ra = xsh_pfits_get_ra_reloffset( header));
    check( rel_dec = xsh_pfits_get_dec_reloffset( header));

    if ( cum_ra == A_cum_ra && cum_dec == A_cum_dec){
      type = "A";
      nod_number = A_number;
    }
    else{
      type = "B";
      nod_number = B_number;
    }
    
    xsh_msg("name %s cumoffset %f %f reloffset %f %f nod_seq_number : %s%d", nod_name,
      cum_ra, cum_dec, rel_ra, rel_dec, type, nod_number);

    xsh_free_propertylist( &header);
 
    check( rmcrh_set = cpl_frameset_new());
    cpl_frameset_insert( rmcrh_set, cpl_frame_duplicate( frame));

    cpl_frameset_iterator_advance(it, 1);
    frame = cpl_frameset_iterator_get_const(it);

    /* finds frame with same nod position to the current one and store them in the same frameset */
    while( frame != NULL){
      check( nod_name = cpl_frame_get_filename( frame));
      check( header = cpl_propertylist_load( nod_name, 0));
      check( nrel_ra = xsh_pfits_get_ra_reloffset( header));
      check( nrel_dec = xsh_pfits_get_dec_reloffset( header));
      xsh_free_propertylist( &header);

      if ( rel_ra == nrel_ra && nrel_dec == rel_dec){
        cpl_frameset_insert( rmcrh_set, cpl_frame_duplicate( frame));
      }
      else{
        break;
      }

      cpl_frameset_iterator_advance(it, 1);
      frame = cpl_frameset_iterator_get_const(it);

    }

    /* Combine frames with same nod position. This to improve statistics and also remove cosmic ray hits */
    sprintf( ftag,"med_%s%d", type, nod_number);
    sprintf(name,"%s.fits",ftag);
    check( crhm_frame = xsh_remove_crh_multiple( rmcrh_set, ftag, stack_par,NULL,instrument, NULL,NULL,1 ));

    check( cpl_frameset_insert( result, crhm_frame));
    xsh_add_temporary_file(name);
    
    if ( cum_ra == A_cum_ra && cum_dec == A_cum_dec){
      A_number++;
    }
    else{
      B_number++;
    }
    xsh_free_frameset( &rmcrh_set);
  }

  cleanup:
    cpl_frameset_iterator_delete(it);
    if ( cpl_error_get_code() != CPL_ERROR_NONE){
      xsh_free_propertylist( &header);
      xsh_free_frameset( &rmcrh_set);
      xsh_free_frameset( &result);
    }
    return result;
}



cpl_frameset* xsh_nod_group_by_reloff2( cpl_frameset *ord_set,xsh_instrument *instrument, xsh_stack_param* stack_par)
{

  cpl_frameset *result = NULL;
  cpl_frameset *tmp_set = NULL;
  cpl_frame *frame = NULL;
  cpl_propertylist *header = NULL;

  const char* nod_name = NULL;

  double rel_ra=0;
  double rel_dec=0;
  double A_cum_ra=0;
  double A_cum_dec=0;
  int A_number=1, B_number =1;
  int nod_number;
  char ftag[40];
  char name[40];
  cpl_vector* vec_ra=NULL;
  cpl_vector* vec_dec=NULL;
  cpl_frame *crhm_frame = NULL;
  double* pvec_ra=NULL;
  double* pvec_dec=NULL;
  int nraw=0;
  int nnod=1;
  int i=0;
  int j=0;
  double frm_ra=0;
  double frm_dec=0;
  XSH_ASSURE_NOT_NULL( ord_set);
  XSH_ASSURE_NOT_NULL( instrument);
  XSH_ASSURE_NOT_NULL( stack_par);
  double tol_ra=0.1;
  double tol_dec=0.1;
  const char *type= NULL;

  nraw=cpl_frameset_get_size(ord_set);
  //cpl_frameset_dump(ord_set,stdout);

  check( result=cpl_frameset_new());

  check( frame = cpl_frameset_get_frame( ord_set,0));

  check( nod_name = cpl_frame_get_filename( frame));
  check( header = cpl_propertylist_load( nod_name, 0));

  check( A_cum_ra = xsh_pfits_get_ra_cumoffset( header));
  check( A_cum_dec = xsh_pfits_get_dec_cumoffset( header));
  check( frm_ra = xsh_pfits_get_ra_cumoffset( header));
  check( frm_dec = xsh_pfits_get_dec_cumoffset( header));

  xsh_free_propertylist( &header);
  vec_ra=cpl_vector_new(nraw);
  vec_dec=cpl_vector_new(nraw);
  pvec_ra=cpl_vector_get_data(vec_ra);
  pvec_dec=cpl_vector_get_data(vec_dec);



  pvec_ra[0]=frm_ra;
  pvec_dec[0]=frm_dec;
  for(i=1;i<nraw;i++) {
    check( frame = cpl_frameset_get_frame( ord_set,i));
    check( header = cpl_propertylist_load( nod_name, 0));
    check( frm_ra = xsh_pfits_get_ra_cumoffset( header));
    check( frm_dec = xsh_pfits_get_dec_cumoffset( header));

    int newtag = 1;
    for(j=0;j<nnod;j++) {
      if( fabs(pvec_ra[j] - frm_ra) < tol_ra &&
          fabs(pvec_dec[j] - frm_dec) < tol_dec )
          {
           newtag = 0;
          }
    }
    if (newtag == 1) {
      pvec_ra[nnod]=frm_ra;
      pvec_dec[nnod]=frm_dec;
      nnod++;
    }
    xsh_free_propertylist( &header);
  }
  cpl_vector_set_size(vec_ra, nnod);
  cpl_vector_set_size(vec_dec, nnod);
  cpl_vector_dump(vec_ra,stdout);
  cpl_vector_dump(vec_dec,stdout);

  while( frame != NULL){
      double cum_ra=0;
      double cum_dec=0;
      //double nrel_ra, nrel_dec;
 
      check( nod_name = cpl_frame_get_filename( frame));
      check( header = cpl_propertylist_load( nod_name, 0));
      check( cum_ra = xsh_pfits_get_ra_cumoffset( header));
      check( cum_dec = xsh_pfits_get_dec_cumoffset( header));
      check( rel_ra = xsh_pfits_get_ra_reloffset( header));
      check( rel_dec = xsh_pfits_get_dec_reloffset( header));

      if ( cum_ra == A_cum_ra && cum_dec == A_cum_dec){
        type = "A";
        nod_number = A_number;
      }
      else{
        type = "B";
        nod_number = B_number;
      }



  }
  while( frame != NULL){
    double cum_ra=0;
    double cum_dec=0;
    double nrel_ra, nrel_dec;

    check( nod_name = cpl_frame_get_filename( frame));
    check( header = cpl_propertylist_load( nod_name, 0));
    check( cum_ra = xsh_pfits_get_ra_cumoffset( header));
    check( cum_dec = xsh_pfits_get_dec_cumoffset( header));
    check( rel_ra = xsh_pfits_get_ra_reloffset( header));
    check( rel_dec = xsh_pfits_get_dec_reloffset( header));

    if ( cum_ra == A_cum_ra && cum_dec == A_cum_dec){
      type = "A";
      nod_number = A_number;
    }
    else{
      type = "B";
      nod_number = B_number;
    }

    xsh_msg("name %s cumoffset %f %f reloffset %f %f nod_seq_number : %s%d", nod_name,
      cum_ra, cum_dec, rel_ra, rel_dec, type, nod_number);

    xsh_free_propertylist( &header);

    check( tmp_set = cpl_frameset_new());
    cpl_frameset_insert( tmp_set, cpl_frame_duplicate( frame));

    check( frame = cpl_frameset_get_next( ord_set));

    while( frame != NULL){
      check( nod_name = cpl_frame_get_filename( frame));
      check( header = cpl_propertylist_load( nod_name, 0));
      check( nrel_ra = xsh_pfits_get_ra_reloffset( header));
      check( nrel_dec = xsh_pfits_get_dec_reloffset( header));
      xsh_free_propertylist( &header);

      if ( rel_ra == nrel_ra && nrel_dec == rel_dec){
        cpl_frameset_insert( tmp_set, cpl_frame_duplicate( frame));
      }
      else{
        break;
      }
      check( frame = cpl_frameset_get_next( ord_set));
    }

    /* Create the remove cosmics frame */
    sprintf( ftag,"med_%s%d", type, nod_number);
    sprintf(name,"%s.fits",ftag);
    check( crhm_frame = xsh_remove_crh_multiple( tmp_set, ftag, stack_par,NULL,instrument, NULL,NULL,1 ));

    check( cpl_frameset_insert( result, crhm_frame));
    xsh_add_temporary_file(name);

    if ( cum_ra == A_cum_ra && cum_dec == A_cum_dec){
      A_number++;
    }
    else{
      B_number++;
    }
    xsh_free_frameset( &tmp_set);
  }

  cleanup:
    if ( cpl_error_get_code() != CPL_ERROR_NONE){
      xsh_free_propertylist( &header);
      xsh_free_frameset( &tmp_set);
      xsh_free_frameset( &result);
    }
    return result;
}


static cpl_frame* xsh_frame_divide_flat( int do_flat, cpl_frame* src, 
  cpl_frame *mflat, const char* tag, xsh_instrument* instr)
{
  cpl_frame *result = NULL;

  if ( do_flat == CPL_TRUE){
    xsh_msg( "Divide by flat");
    xsh_msg("sci name: %s flat name: %s",cpl_frame_get_filename(src),cpl_frame_get_filename(mflat));
    check( result = xsh_divide_flat( src, mflat, tag, instr));
  }
  else{
	xsh_msg("divide ok1 %s",cpl_frame_get_filename(src));
	xsh_pre* xframe = xsh_pre_load( src, instr);
	char fname[FILENAME_MAX];
	sprintf(fname,"tmp_%s",cpl_frame_get_filename(src));
	result = xsh_pre_save(xframe,fname,cpl_frame_get_tag(src),1);
	cpl_frame_set_filename(result,fname);
	xsh_msg("fname=%s",fname);
	xsh_pre_free(&xframe);
    //check( result = cpl_frame_duplicate( src));
  }

  cleanup:
    return result;
}

/*
static cpl_frame*
xsh_nod_median_correct_ima_per_wavelength(cpl_frame *input)
{


  int next=0;
  int i=0;
  int j=0;
  int k=0;

  cpl_image* data=NULL;
  cpl_image* errs=NULL;
  cpl_image* qual=NULL;
  cpl_frame* result=NULL;

  const char* fname=NULL;
  char fname_new[256];
  cpl_propertylist* hdata=NULL;
  cpl_propertylist* herrs=NULL;
  cpl_propertylist* hqual=NULL;
  int sx=0;
  int sy=0;
  double median=0;
  //int naxis1=0;
  float* pdata=NULL;

  next = cpl_frame_get_nextensions(input);
  fname=cpl_frame_get_filename(input);


  sprintf(fname_new,"MED_COR_%s",fname);
  result=cpl_frame_duplicate(input);
  cpl_frame_set_filename(result,fname_new);

  xsh_msg("ok1");
  hdata=cpl_propertylist_load(fname,0);
  //naxis1=xsh_pfits_get_naxis1(hdata);
  xsh_free_propertylist(&hdata);

  for(k=0; k<next;k+=3) {

    data=cpl_image_load(fname,XSH_PRE_DATA_TYPE,0,k);
    errs=cpl_image_load(fname,XSH_PRE_ERRS_TYPE,0,k+1);
    qual=cpl_image_load(fname,XSH_PRE_QUAL_TYPE,0,k+2);

    pdata=cpl_image_get_data_float(data);
    hdata=cpl_propertylist_load(fname,k);
    herrs=cpl_propertylist_load(fname,k+1);
    hqual=cpl_propertylist_load(fname,k+2);

    sx=cpl_image_get_size_x(data);
    sy=cpl_image_get_size_y(data);
    xsh_msg("ok5");
    // correct the image by median subtraction at each wavelength (y position)
    for(i=1;i<=sx;i++) {
      median=cpl_image_get_median_window(data,i,1,i,sy);
      for(j=0;j<sy;j++) {
        pdata[j*sx+i-1]-=median;
      }
    }

    if(k==0) {
      cpl_image_save(data, fname_new, XSH_PRE_DATA_BPP, hdata, CPL_IO_DEFAULT);
      cpl_image_save(errs, fname_new, XSH_PRE_ERRS_BPP, herrs, CPL_IO_EXTEND);
      cpl_image_save(qual, fname_new, XSH_PRE_QUAL_BPP, hqual, CPL_IO_EXTEND);
    } else {
      cpl_image_save(data, fname_new, XSH_PRE_DATA_BPP, hdata, CPL_IO_EXTEND);
      cpl_image_save(errs, fname_new, XSH_PRE_ERRS_BPP, herrs, CPL_IO_EXTEND);
      cpl_image_save(qual, fname_new, XSH_PRE_QUAL_BPP, hqual, CPL_IO_EXTEND);
    }

    xsh_free_image(&data);
    xsh_free_image(&errs);
    xsh_free_image(&qual);
    xsh_free_propertylist(&hdata);
    xsh_free_propertylist(&herrs);
    xsh_free_propertylist(&hqual);

  }

  //cleanup:
   xsh_free_image(&data);
   xsh_free_image(&errs);
   xsh_free_image(&qual);
   xsh_free_propertylist(&hdata);
   xsh_free_propertylist(&herrs);
   xsh_free_propertylist(&hqual);
  return result;
}
*/



static cpl_frame*
xsh_nod_median_correct_list_per_wavelength(cpl_frame *frame_i, xsh_instrument* inst)
{

  cpl_frame* frame_o=NULL;
  xsh_rec_list* list_o=NULL;

  const char* fname_i=NULL;
  char fname_o[256];
  cpl_image* image=NULL;
  const char* tag_o;
  int next=0;
  int i=0;
  int j=0;
  int k=0;
  int sx=0;
  int sy=0;
  float* pdata=NULL;
  double median=0;

  /* check input parameters */
  XSH_ASSURE_NOT_NULL(frame_i);
  XSH_ASSURE_NOT_NULL(inst);

  next = cpl_frame_get_nextensions(frame_i);
  fname_i=cpl_frame_get_filename(frame_i);

  list_o=xsh_rec_list_load(frame_i,inst);

  for(k=0; k<next;k++) {

    sx=list_o->list[k].nlambda;
    sy=list_o->list[k].nslit;

    pdata= xsh_rec_list_get_data1(list_o,k);

    image=cpl_image_wrap_float(sx,sy,pdata);
    /* median correct the image at each wavelength (y position) */
    for(i=1;i<=sx;i++) {
      median=cpl_image_get_median_window(image,i,1,i,sy);
      for(j=0;j<sy;j++) {
        pdata[j*sx+i-1]-=median;
      }
    }
    cpl_image_unwrap(image);

  }

  tag_o=cpl_frame_get_tag(frame_i);
  sprintf(fname_o,"MED_COR_%s",fname_i);
  frame_o=xsh_rec_list_save(list_o,fname_o,tag_o,1);
  cpl_frame_set_filename(frame_o,fname_o);
  xsh_add_temporary_file(fname_o);

  cleanup:
  xsh_rec_list_free(&list_o);
  return frame_o;
}


static cpl_error_code
xsh_nod_rectify_and_shift_with_key(const char* nod_name,
                                   const char* qual_name,
                                   const char* rec_prefix,
                                   cpl_frame* frame2D,
                                   cpl_frame* order_tab_edges,
                                   cpl_frame* wave_tab,
                                   cpl_frame* model_config_frame,
                                   cpl_frame* spectral_format,
                                   cpl_frame* disp_tab_frame,
                                   xsh_instrument* instrument,
                                   const int corr_sky,
                                   xsh_rectify_param *rectify_par,
				   double** ref_ra,
				   double** ref_dec,
                                   cpl_frame **shift2_frame,
                                   cpl_frame **shift1_frame)

{

  //HERE BUG
   char file_name[256];
   cpl_frame * rec2_frame = NULL ; /**< Output of xsh_rectfiy */
   cpl_frame * rec2eso_frame = NULL ;
   cpl_frame * rec2tab_frame = NULL ;
   cpl_frame *shift2eso_frame = NULL;
   cpl_frame * rec1_frame = NULL ;
   cpl_frame *shift1eso_frame = NULL;
   cpl_frame * rec2_frame_median_correct=NULL;

   /* Localization should be done following the order trace, not rectifying */
   sprintf(file_name,"REC2_%s_%s",qual_name,nod_name);
   check(rec2_frame = xsh_rectify( frame2D,order_tab_edges,
                                   wave_tab,model_config_frame,instrument, 
                                   rectify_par,spectral_format,disp_tab_frame,
                                   file_name,&rec2eso_frame,&rec2tab_frame,
                                   rec_prefix));
   xsh_add_temporary_file(file_name);

   sprintf(file_name,"SHIFT2_%s_%s",qual_name,nod_name);

   if(corr_sky) {
     rec2_frame_median_correct=xsh_nod_median_correct_list_per_wavelength(rec2_frame,instrument);
   

     check( *shift2_frame = shift_with_kw( rec2_frame_median_correct, instrument,rectify_par,
					   file_name, &shift2eso_frame, 
					   ref_ra,ref_dec, 0));
     xsh_add_temporary_file(file_name);
     sprintf(file_name,"REC1_FAST_%s_%s",qual_name,nod_name);
     check( rec1_frame = xsh_rec_list_frame_invert( rec2_frame_median_correct, file_name,
						    instrument));
     xsh_add_temporary_file(cpl_frame_get_filename(rec1_frame));

   } else {
     check( *shift2_frame = shift_with_kw( rec2_frame, instrument,rectify_par,
					   file_name, &shift2eso_frame, 
					   ref_ra,ref_dec, 0));
     xsh_add_temporary_file(file_name);
     sprintf(file_name,"REC1_FAST_%s_%s",qual_name,nod_name);
     check( rec1_frame = xsh_rec_list_frame_invert( rec2_frame, file_name,
						    instrument));
     xsh_add_temporary_file(cpl_frame_get_filename(rec1_frame));

   }


   sprintf(file_name,"SHIFT1_FAST_%s_%s",qual_name,nod_name);
   check( *shift1_frame = shift_with_kw( rec1_frame, instrument,
                                        rectify_par, file_name, 
                                        &shift1eso_frame, ref_ra,
                                        ref_dec, 1));
   xsh_add_temporary_file(file_name);
  cleanup:

    xsh_free_frame( &rec1_frame);
    xsh_free_frame( &rec2_frame);
    xsh_free_frame( &shift1eso_frame);
    xsh_free_frame( &shift2eso_frame);
    xsh_free_frame( &rec2eso_frame);
    xsh_free_frame( &rec2tab_frame);
    xsh_free_frame( &rec2_frame_median_correct);
   return cpl_error_get_code();
}

cpl_frameset*
xsh_scired_slit_nod_fast(
			 cpl_frameset *nod_set,
			 cpl_frame* spectral_format,
			 cpl_frame* master_flat,
			 cpl_frame* order_tab_edges,
                         cpl_frame* wave_tab,
                         cpl_frame* model_config_frame,
                         cpl_frame* disp_tab_frame,
                         cpl_frame* wavemap,
			 xsh_instrument* instrument,
                         xsh_remove_crh_single_param *crh_single_par,
                         xsh_rectify_param *rectify_par,
                         const int do_flatfield,
                         const int corr_sky,
                         const int compute_eff, 
                         const char* rec_prefix,
                         cpl_frameset **comb_eff_set)

{

  /* Intermediate frames */
  //cpl_frame *rm_crh = NULL;
  cpl_frame * div2_frame = NULL ; 
  cpl_frame * eff2_frame = NULL ; 
  cpl_frame *shift1_frame = NULL;
  cpl_frame *shift2_frame = NULL;
  cpl_frame *shift1_eff_frame = NULL;
  cpl_frame *shift2_eff_frame = NULL;
  double* ref_ra=NULL;
  double* ref_dec=NULL;
  double* ref_eff_ra=NULL;
  double* ref_eff_dec=NULL;
  cpl_frameset* comb_set=NULL;

  /* Output Frames (results)*/
  int i=0;
  int nb_pairs=0;

  xsh_msg("Method fast");
  check( comb_set = cpl_frameset_new());

  if(compute_eff) {
     check( *comb_eff_set = cpl_frameset_new());
  }

  /* Now subtract B to A */
  check( nb_pairs = cpl_frameset_get_size( nod_set));

  for( i = 0; i< nb_pairs; i++){
    cpl_frame *nod_frame = NULL;
    const char* nod_name = NULL;
    char tag[256];
    char name[256];

    nod_frame = cpl_frameset_get_frame( nod_set, i);
    nod_name = cpl_frame_get_filename( nod_frame); 
    xsh_msg_dbg_high( "***** Frame %s", nod_name);

    /* 
       No background subtraction in nodding  because bkg goes away with A-B 
    */



    /* we now correct the absolute frame back to original layout */
    /* divide by flat */
    sprintf(tag,"DIV2_FLATFIELD_%s", xsh_instrument_arm_tostring(instrument)) ;
    sprintf(name,"%s.fits",tag);
    check( div2_frame =xsh_frame_divide_flat( do_flatfield, nod_frame, master_flat,
					tag, instrument));
    xsh_add_temporary_file(name);

    /* Rectify */
    check(xsh_nod_rectify_and_shift_with_key(nod_name,"RECTIFIED",rec_prefix,
                                             div2_frame,order_tab_edges,
                                             wave_tab,model_config_frame,
                                             spectral_format,
                                             disp_tab_frame,
                                             instrument,corr_sky,
                                             rectify_par,&ref_ra,&ref_dec,
                                             &shift1_frame,&shift2_frame));

    cpl_frameset_insert( comb_set, shift2_frame);
    cpl_frameset_insert( comb_set, shift1_frame);

    if(compute_eff) {  
       if(disp_tab_frame != NULL) {
       int conserve_flux=rectify_par->conserve_flux;

       sprintf(tag,"NOCRH_EFF_%s",xsh_instrument_arm_tostring(instrument)) ;
       xsh_msg("before %s",cpl_frame_get_filename(nod_frame));
       check( eff2_frame =xsh_frame_divide_flat(0, nod_frame, master_flat,
                                                tag, instrument));
       xsh_msg("after %s",cpl_frame_get_filename(eff2_frame));
       rectify_par->conserve_flux=1;
       check(xsh_nod_rectify_and_shift_with_key(nod_name,"EFF",rec_prefix,
                                                eff2_frame,order_tab_edges,
                                                wave_tab,model_config_frame,
                                                spectral_format,
                                                disp_tab_frame,
                                                instrument,corr_sky,
                                                rectify_par,
						&ref_eff_ra,&ref_eff_dec,
                                                &shift1_eff_frame,
                                                &shift2_eff_frame));

       rectify_par->conserve_flux=conserve_flux;  
       cpl_frameset_insert( *comb_eff_set, shift2_eff_frame);
       cpl_frameset_insert( *comb_eff_set, shift1_eff_frame);
       xsh_free_frame( &eff2_frame);

       }
    }
    //xsh_free_frame( &rm_crh);
    xsh_free_frame( &div2_frame);


  } /* end loop on input pairs */

  cleanup:
    XSH_FREE( ref_ra);
    XSH_FREE( ref_dec);
    XSH_FREE( ref_eff_ra);
    XSH_FREE( ref_eff_dec);
    xsh_free_frame( &eff2_frame);
    xsh_free_frame( &div2_frame);
    return comb_set;
}




cpl_frameset*
xsh_scired_slit_nod_accurate(
			     cpl_frameset *nod_set,
			     cpl_frame* spectral_format,
                             cpl_frame* master_flat,
                             cpl_frame* order_tab_edges,
                             cpl_frame* wave_tab,
                             cpl_frame* model_config_frame,
                             cpl_frame* disp_tab_frame,
                             cpl_frame* wavemap,
                             cpl_frame *skymask_frame,
                             xsh_instrument* instrument,
                             xsh_remove_crh_single_param *crh_single_par,
                             xsh_rectify_param *rectify_par,
                             xsh_localize_obj_param *loc_obj_par,
                             const char *throw_name,
                             const int do_flatfield,
                             const char* rec_prefix
			     )
{
  int i=0;
  cpl_frame * a_b = NULL;

  /* all what follows regards the old-slow method */
  char file_tag[40];
  char file_name[256];
  //int npairs=0;
  int nb_nod=0;
  double *throw_shift = NULL;
  double *throw_tab = NULL;
  FILE* throw_file = NULL;

  cpl_frame * loc_a_b = NULL, * loc_b_a = NULL ;
  cpl_frame * loc_a_b_0 = NULL;
  
  cpl_frameset *comb_set = NULL;

  int file_exist=0;

  xsh_msg("Method accurate");
  check( comb_set = cpl_frameset_new());

  check( nb_nod = cpl_frameset_get_size( nod_set));
 
  file_exist=access(throw_name, F_OK);
  if (file_exist != 0) {
     xsh_msg_error("The Name %s of ASCII file containing the list of throw shifts with respect to the first exposure was not found. Exit.",throw_name);
     cpl_error_set(cpl_func, CPL_ERROR_FILE_NOT_FOUND);
     goto cleanup;
  }

  if ( strcmp( throw_name, "") != 0 && file_exist ==0 ){
    char throw_line[200];
    int iline;

    xsh_msg("Load Throw shifts from file %s", throw_name);
    throw_file = fopen( throw_name, "r");

    XSH_CALLOC( throw_tab, double, nb_nod);

    iline=0;

    while (fgets( throw_line, 200, throw_file) != NULL){
      char shiftval[200];

      /* Note: update the string format (the %__s) if shiftval changes size.
       * Remember: field width must equal 1 less than sizeof(shiftval). */
      sscanf( throw_line, "%199s",shiftval);
      if (iline < nb_nod){
        throw_tab[iline] = atof( shiftval);
      }
      iline++;
    }
    if (iline != nb_nod){
      xsh_error_msg("Invalid number of lines in ASCII file %s : %d - expected number : %d", 
        throw_name, iline, nb_nod);
    }
    fclose( throw_file);
    throw_file = NULL;
  }

  /* For each  of frames */
  for( i = 0; i<nb_nod ; i++) {
    //cpl_frame * rm_crh = NULL ;
    cpl_frame * divided = NULL ;
    cpl_frame * shifted_a_b = NULL;
    cpl_frame * shifted_a_b_eso = NULL;
    cpl_frame * shifted_a_b_tab = NULL;
    cpl_frame *inv_shifted_a_b = NULL;
    cpl_frame *loc_rec = NULL;
    cpl_frame *loc_rec_eso = NULL;
    cpl_frame *loc_rec_tab = NULL;
    cpl_frame *inv_loc_rec = NULL;
    char str[16] ;
    //int mode =0;

    if (throw_tab != NULL){
      throw_shift = &throw_tab[i];
    }

    if (i%2 == 0){
      sprintf( str, "AB_%d_%s", i/2, xsh_instrument_arm_tostring(instrument)) ;
      //mode =0;
    }
    else{
      sprintf( str, "BA_%d_%s", i/2, xsh_instrument_arm_tostring(instrument)) ;
      //mode=1;
    }
    check( a_b = cpl_frameset_get_frame( nod_set, i));
    xsh_msg_dbg_high( "***** Frame %s", cpl_frame_get_filename( a_b ) ) ;

    /* remove_crh : if we have done multiple don't do single
    xsh_msg( "Remove crh (single frame)" ) ;
    sprintf(file_tag, "SLIT_NOD_NOCRH_%s",str) ;

    check( rm_crh = xsh_abs_remove_crh_single(a_b, instrument,
      crh_single_par, file_tag));
    */
    /*divide by flat field */
    sprintf(file_tag,"SLIT_NOD_NOCRH_FF_%s", str);
    check( divided = xsh_frame_divide_flat( do_flatfield, a_b,master_flat, file_tag,
      instrument));

    if ( i > 1 && throw_shift == NULL){
      if (i%2 == 0){
        xsh_msg("TEST %d : on fait loc_ab et loc_ba", i);
        sprintf(file_name,"LOC_REC_%s.fits", str);
        check( loc_rec = xsh_rectify( divided, order_tab_edges,
                                    wave_tab, model_config_frame, instrument,
                                    rectify_par, spectral_format, disp_tab_frame,
                                    file_name, &loc_rec_eso, &loc_rec_tab, rec_prefix));
        xsh_msg( "Localize the object (A%d)", i/2);
        sprintf( file_name,"LOCALIZE_%s.fits", str);
        check( loc_a_b = xsh_localize_obj( loc_rec, skymask_frame, instrument, loc_obj_par,
          NULL, file_name));
        xsh_add_temporary_file(file_name);

        xsh_msg( "Negative rectify");
        sprintf(file_name,"DRL_INV_LOC_REC_%s", str);
      check( inv_loc_rec = xsh_rec_list_frame_invert( loc_rec,
        file_name, instrument));

      xsh_msg( "Localize the object (B%d)", i/2);
      sprintf(file_name,"INV_LOCALIZE_%s.fits", str);
      check( loc_b_a = xsh_localize_obj( inv_loc_rec, skymask_frame, instrument, loc_obj_par,
        NULL, file_name));
      }
      else{
        xsh_msg("TEST %d : loc_ab = loc_ba", i);
        loc_a_b = loc_b_a;
      }
    }
    /* Rectify and shift */
    xsh_msg( "Rectify and shift");
    sprintf(file_name,"SHIFT_REC_NOCRH_%s.fits", str);

    check( shifted_a_b = xsh_rectify_and_shift( divided,order_tab_edges,
                                                 wave_tab,
                                                 model_config_frame,
                                                 instrument,
                                                 rectify_par,
                                                 spectral_format,
                                                 loc_a_b,
                                                 loc_a_b_0,
                                                 throw_shift,
                                                 disp_tab_frame,
                                                 file_name,
                                                 &shifted_a_b_eso,
                                                 &shifted_a_b_tab));
    xsh_free_frame( &loc_a_b);

    if ( i==0 && throw_shift == NULL){
      xsh_msg( "Localize the object (A0)");
      sprintf(file_name,"LOCALIZE_%s.fits", str);
      check( loc_a_b_0 = xsh_localize_obj( shifted_a_b, skymask_frame, instrument, loc_obj_par,
        NULL, file_name));
      xsh_add_temporary_file(file_name);

      xsh_msg( "Negative rectify");
      sprintf(file_name,"DRL_INV_LOC_REC_%s", str);
      check( inv_shifted_a_b = xsh_rec_list_frame_invert( shifted_a_b, 
        file_name, instrument));
      xsh_msg( "Localize the object (B0)");
      sprintf(file_name,"INV_LOCALIZE_%s.fits", str);
      check( loc_a_b = xsh_localize_obj( inv_shifted_a_b, skymask_frame, instrument, loc_obj_par,
        NULL, file_name));
    }
    check( cpl_frameset_insert( comb_set, shifted_a_b));

    //xsh_free_frame( &rm_crh);
    xsh_free_frame( &divided);
    xsh_free_frame( &shifted_a_b_eso);
    xsh_free_frame( &shifted_a_b_tab);
    xsh_free_frame( &inv_shifted_a_b);
    xsh_free_frame( &loc_rec);
    xsh_free_frame( &loc_rec_eso);
    xsh_free_frame( &loc_rec_tab);
    xsh_free_frame( &inv_loc_rec);
  } /* end loop on each pair */

  cleanup:
    if (throw_file != NULL) fclose(throw_file);
    if ( cpl_error_get_code() != CPL_ERROR_NONE || file_exist!=0){
      xsh_free_frameset( &comb_set);
    }
    xsh_free_frame( &loc_a_b_0);
    xsh_free_frame( &loc_a_b);
    XSH_FREE( throw_tab);
    return comb_set;


}

cpl_error_code
xsh_scired_get_proper_maps(cpl_frameset* raws, cpl_frameset* calib,
                           cpl_frame* order_tab_edges,cpl_frame* master_flat,
                           cpl_frame* model_config_frame,cpl_frame* disp_tab,
                           xsh_instrument* instrument,const int do_computemap,
                           const char* rec_prefix, cpl_frame** wavemap,
                           cpl_frame** slitmap)
{

    /* create proper size wave and slit maps */
    cpl_frame* ref_frame=NULL;
    int recipe_use_model=FALSE;
    if (xsh_mode_is_physmod(calib,instrument)){
       ref_frame=cpl_frameset_get_frame(raws,0);
     }
     else{
       ref_frame = master_flat;
     }
     check( xsh_check_get_map( disp_tab, order_tab_edges,
                   ref_frame, model_config_frame, calib, instrument,
                   do_computemap, recipe_use_model, rec_prefix,
                   wavemap, slitmap));
cleanup:
return cpl_error_get_code();

}

cpl_error_code
xsh_get_normal_calibs(cpl_frameset* calib,xsh_instrument* instrument,
		const char* recipe_id,int pscan,cpl_frame** spectral_format,
		cpl_frame** master_bias,
		cpl_frame** bpmap,cpl_frame** order_tab_edges,cpl_frame** master_flat)
{

	check( *spectral_format = xsh_find_spectral_format( calib, instrument));


	if(pscan==0) {
		/* In UVB and VIS mode */
		if ( xsh_instrument_get_arm(instrument) != XSH_ARM_NIR){
			/* RAWS frameset must have only one file */
			check(*master_bias = xsh_find_master_bias( calib, instrument));
		}
	}

	check(*bpmap=xsh_check_load_master_bpmap(calib,instrument,recipe_id));

	check( *order_tab_edges = xsh_find_order_tab_edges( calib, instrument));

	if( NULL == (*master_flat = xsh_find_master_flat( calib,instrument))) {
		xsh_msg_error("You must provide a %s frame in input",
				XSH_GET_TAG_FROM_MODE ( XSH_MASTER_FLAT, instrument));
		goto cleanup;
	}

	cleanup:
	return cpl_error_get_code();
}

cpl_error_code
xsh_get_dispersion_calibs(cpl_frameset* calib, xsh_instrument* instrument,
		const int do_computemap,
		cpl_frame** model_config_frame, cpl_frame** wave_tab,
		cpl_frame** wavemap)
{
      int recipe_use_model=FALSE;
	  cpl_boolean mode_phys;
	  mode_phys=xsh_mode_is_physmod(calib,instrument);

	  /* one should have either model config frame or wave sol frame */
	  if(mode_phys) {
	    recipe_use_model = TRUE;
	    if((*model_config_frame = xsh_find_frame_with_tag(calib,
							      XSH_MOD_CFG_OPT_AFC,
							      instrument)) == NULL) {

	      xsh_error_reset();
	      if ((*model_config_frame = xsh_find_frame_with_tag(calib,XSH_MOD_CFG_OPT_2D,
								 instrument)) == NULL) {
	        xsh_error_reset();

	        if ((*model_config_frame = xsh_find_frame_with_tag(calib,XSH_MOD_CFG_TAB,
								   instrument)) == NULL) {
		  xsh_error_reset();
	        } else {
	           xsh_msg("RECIPE USE REFERENCE MODEL");
	        }
	      } else {
	         xsh_msg("RECIPE USE OPTIMISED 2D MODEL");
	      }
	    } else {
	       xsh_msg("RECIPE USE OPTIMISED AFC MODEL");
	    }
	  } else {
	    xsh_msg("RECIPE USE WAVE SOLUTION");
	    check( *wave_tab = xsh_find_wave_tab( calib, instrument));
	    recipe_use_model = FALSE;
	  }

	  XSH_ASSURE_NOT_ILLEGAL( model_config_frame != NULL || wave_tab != NULL);

	  if(do_computemap && recipe_use_model==FALSE) {
	    check( *wavemap = xsh_find_wavemap( calib, instrument));
	  }
	cleanup:
		return cpl_error_get_code();
}

static cpl_error_code
xsh_get_response_calibs(cpl_frameset* calib, xsh_instrument* instrument,
		const int use_sky_mask, cpl_frame** disp_tab_frame,
		cpl_frame** response_ord_frame, cpl_frame** frm_atmext,
		cpl_frame** skymask_frame) {

	/* to compute efficiency */
	if(NULL == (*disp_tab_frame = xsh_find_disp_tab( calib, instrument))) {
		xsh_msg("To compute efficiency, you must provide a DISP_TAB_ARM input");
	}

	if ( use_sky_mask == TRUE){
		xsh_msg("Using sky mask");
		check( *skymask_frame = xsh_find_frame_with_tag( calib, XSH_SKY_LINE_LIST,
				instrument));
	}

	check( *response_ord_frame = xsh_find_frame_with_tag(calib,
			XSH_RESPONSE_MERGE1D_SLIT, instrument));

	if(*response_ord_frame != NULL) {
		*frm_atmext=xsh_find_frame_with_tag(calib,XSH_ATMOS_EXT,instrument);
		if(*frm_atmext==NULL) {
			xsh_msg_error("Provide atmospheric extinction frame");
		}
	}

	cleanup:
	return cpl_error_get_code();
}

cpl_error_code
xsh_get_calibs_to_flux_calibrate(cpl_frameset* calib,
		xsh_instrument* instrument, cpl_frame** response_ord_frame,
		cpl_frame** frm_atmext)
{


	if((*response_ord_frame=xsh_find_frame_with_tag(calib,XSH_RESPONSE_MERGE1D_SLIT,
			instrument)) == NULL ) {
		check( *response_ord_frame = xsh_find_frame_with_tag(calib,
				XSH_MRESPONSE_MERGE1D_SLIT,
				instrument));
	}
	if(*response_ord_frame != NULL) {
		*frm_atmext=xsh_find_frame_with_tag(calib,XSH_ATMOS_EXT,instrument);
		if(*frm_atmext==NULL) {
			xsh_msg_error("Provide atmospheric extinction frame");
		}
	}
	cleanup:
	return cpl_error_get_code();
}
//PIPPO
cpl_error_code
xsh_scired_slit_nod_get_calibs(cpl_frameset* raws,
                               cpl_frameset* calib,
                   xsh_instrument* instrument,
                   cpl_frame** bpmap,
                   cpl_frame** master_bias,
                   cpl_frame** master_flat,
                   cpl_frame** order_tab_edges,
                   cpl_frame** wave_tab,
                   cpl_frame** model_config_frame,
                   cpl_frame** wavemap,
                   cpl_frame** slitmap,
                   cpl_frame** disp_tab_frame,
                   cpl_frame** spectral_format,
                               cpl_frame** skymask_frame,
                               cpl_frame** response_ord_frame,
                               cpl_frame** frm_atmext,
                               int do_computemap,
                               int use_skymask,
                               int pscan,
                   const char* rec_prefix,
                   const char* recipe_id)

{

  xsh_get_normal_calibs(calib, instrument, recipe_id, pscan, spectral_format,
			master_bias, bpmap, order_tab_edges, master_flat);
  int recipe_use_model=FALSE;
  cpl_frame* ref_frame=NULL;
  cpl_boolean mode_phys;
  mode_phys=xsh_mode_is_physmod(calib,instrument);


  /* one should have either model config frame or wave sol frame */
  if(mode_phys) {
    recipe_use_model = TRUE;
    if((*model_config_frame = xsh_find_frame_with_tag(calib,
                              XSH_MOD_CFG_OPT_AFC,
                              instrument)) == NULL) {

      xsh_error_reset();
      if ((*model_config_frame = xsh_find_frame_with_tag(calib,XSH_MOD_CFG_OPT_2D,
                             instrument)) == NULL) {
        xsh_error_reset();

        if ((*model_config_frame = xsh_find_frame_with_tag(calib,XSH_MOD_CFG_TAB,
                               instrument)) == NULL) {
      xsh_error_reset();
        } else {
           xsh_msg("RECIPE USE REFERENCE MODEL");
        }
      } else {
         xsh_msg("RECIPE USE OPTIMISED 2D MODEL");
      }
    } else {
       xsh_msg("RECIPE USE OPTIMISED AFC MODEL");
    }
  } else {
    xsh_msg("RECIPE USE WAVE SOLUTION");
    check( *wave_tab = xsh_find_wave_tab( calib, instrument));
    recipe_use_model = FALSE;
  }

  XSH_ASSURE_NOT_ILLEGAL( model_config_frame != NULL || wave_tab != NULL);


  if(do_computemap && recipe_use_model==FALSE) {
    check( *wavemap = xsh_find_wavemap( calib, instrument));
  }
  /* to compute efficiency */
  if(NULL == (*disp_tab_frame = xsh_find_disp_tab( calib, instrument))) {
    xsh_msg("To compute efficiency, you must provide a DISP_TAB_ARM input");
  }

  if ( recipe_use_model){
    ref_frame=cpl_frameset_get_frame(raws,0);
  }
  else{
    ref_frame = *master_flat;
  }
  check( xsh_check_get_map( *disp_tab_frame, *order_tab_edges,
                ref_frame, *model_config_frame, calib, instrument,
                do_computemap, recipe_use_model, rec_prefix,
                wavemap, slitmap));


  if ( use_skymask == TRUE){
    xsh_msg("Using sky mask");
    check( *skymask_frame = xsh_find_frame_with_tag( calib, XSH_SKY_LINE_LIST,
                             instrument));
  }

  xsh_get_calibs_to_flux_calibrate(calib, instrument, response_ord_frame,
		  frm_atmext);

 cleanup:
  return cpl_error_get_code();
}



cpl_error_code
xsh_respon_slit_nod_get_calibs(cpl_frameset* calib,
			       xsh_instrument* instrument,
			       cpl_frame** bpmap,
			       cpl_frame** master_bias,
			       cpl_frame** master_flat,
			       cpl_frame** order_tab_edges,
			       cpl_frame** wave_tab,
			       cpl_frame** model_config_frame,
			       cpl_frame** wavemap,
			       cpl_frame** slitmap,
			       cpl_frame** disp_tab_frame,
			       cpl_frame** spectral_format,
                               cpl_frame** skymask_frame,
                               cpl_frame** response_ord_frame,
                               cpl_frame** frm_atmext,
                               int do_computemap,
                               int use_skymask,
                               int pscan,
			       const char* rec_prefix,
			       const char* recipe_id)

{

	xsh_get_normal_calibs(calib, instrument, recipe_id, pscan, spectral_format,
			master_bias, bpmap, order_tab_edges, master_flat);

	xsh_get_dispersion_calibs(calib, instrument, do_computemap,
			model_config_frame, wave_tab, wavemap);

	xsh_get_response_calibs(calib, instrument, use_skymask, disp_tab_frame,
			response_ord_frame, frm_atmext, skymask_frame);

	cleanup:
	return cpl_error_get_code();
}

/* for the moment not used */
/** 
  @brief monitor param values
  @param rectify_par rectify param structure
  @param loc_obj_par localizzation object param
 */
static cpl_error_code 
xsh_scired_nod_params_monitor(xsh_rectify_param * rectify_par,
                   xsh_localize_obj_param * loc_obj_par)
{



  xsh_msg_dbg_low("rectify params: radius=%g bin_lambda=%g bin_space=%g",
	  rectify_par->rectif_radius,rectify_par->rectif_bin_lambda,
	  rectify_par->rectif_bin_space);

  xsh_msg_dbg_low("localize params: chunk_nb=%d nod_step=%g",
	  loc_obj_par->loc_chunk_nb,loc_obj_par->nod_step);

  return cpl_error_get_code();

}




cpl_error_code
xsh_scired_nod_get_parameters(cpl_parameterlist* parameters,
			      xsh_instrument* instrument,
			      xsh_remove_crh_single_param** crh_single_par,
			      xsh_rectify_param** rectify_par,
			      xsh_extract_param** extract_par,
			      xsh_combine_nod_param** combine_nod_par,
			      xsh_slit_limit_param** slit_limit_par,
			      xsh_localize_obj_param** loc_obj_par,
			      int* rectify_fast, int* pscan,
                              int* generate_sdp_format,
                              const char* rec_id
			      )


{
  check( *loc_obj_par = xsh_parameters_localize_obj_get(rec_id,
							parameters));
  check( *rectify_par = xsh_parameters_rectify_get(rec_id,
						   parameters));
  check( *rectify_fast = xsh_parameters_rectify_fast_get(rec_id,
							 parameters));
  check( *crh_single_par = xsh_parameters_remove_crh_single_get(rec_id,
								parameters));
  check( *extract_par=xsh_parameters_extract_get(rec_id, parameters));
  check( *combine_nod_par = xsh_parameters_combine_nod_get(rec_id,
							  parameters)) ;
  check( *slit_limit_par = xsh_parameters_slit_limit_get(rec_id,
							 parameters));

  check(xsh_rectify_params_set_defaults(parameters,rec_id,instrument,*rectify_par));

  check( xsh_scired_nod_params_monitor(*rectify_par,*loc_obj_par));
  check( *pscan=xsh_parameters_get_int(parameters,rec_id,"pre-overscan-corr"));

  if (xsh_parameters_find(parameters, rec_id, "generate-SDP-format") != NULL) {
    check( *generate_sdp_format = xsh_parameters_get_boolean(parameters, rec_id,
                                                       "generate-SDP-format"));
  }

  cleanup:
    return cpl_error_get_code();
}


cpl_error_code
xsh_flux_calibrate1D(cpl_frame* rect1D,
                   cpl_frame* atmext,
                   cpl_frame* response,
                   int mpar,
                   xsh_instrument* inst,
                   const char* rec_prefix,
                   cpl_frame** fcal_rect_1D,
                   cpl_frame** fcal_1D)
{

  char file_tag[256];
  char file_name[256];
  char arm_str[8] ;
  cpl_frame* nrm_1D=NULL;
  const char* tag=NULL;


  tag=cpl_frame_get_tag(rect1D);
  sprintf(arm_str,"%s",xsh_instrument_arm_tostring(inst));
  xsh_msg("tag=%s",tag);
  if(strstr(tag,XSH_ORDER_OXT1D) == NULL) {
     sprintf(file_tag,"%s_%s_%s",rec_prefix,XSH_NORM_ORDER1D,arm_str);
  } else {
     sprintf(file_tag,"%s_%s_%s",rec_prefix,XSH_NORM_OXT1D,arm_str);
  }
  xsh_msg("file_tag1=%s",file_tag);
  sprintf(file_name,"%s.fits",file_tag);
  xsh_add_temporary_file(file_name);

  check(nrm_1D=xsh_normalize_spectrum_ord(rect1D,atmext,1,inst,file_tag));
  if(strstr(tag,XSH_ORDER_OXT1D) == NULL) {
     sprintf(file_tag,"%s_%s_%s",rec_prefix,XSH_FLUX_ORDER1D,arm_str);
  } else {
     sprintf(file_tag,"%s_%s_%s",rec_prefix,XSH_FLUX_OXT1D,arm_str);
  }
  sprintf(file_name,"%s.fits",file_tag);
  //xsh_add_temporary_file(file_name);

  check(*fcal_rect_1D=xsh_util_multiply_by_response_ord(nrm_1D,response,file_tag));
  check(*fcal_1D= xsh_merge_ord(*fcal_rect_1D,inst,mpar,rec_prefix));
  xsh_msg("file_tag2=%s",file_tag);


cleanup:
  xsh_free_frame(&nrm_1D);
  return cpl_error_get_code();

}



cpl_error_code
xsh_flux_calibrate2D(cpl_frame* rect2D,
                   cpl_frame* atmext,
                   cpl_frame* response,
                   int mpar,
                   xsh_instrument* inst,
                   const char* rec_prefix,
                   cpl_frame** fcal_rect_2D,
                   cpl_frame** fcal_2D)
{


  char file_tag[256];
  char file_name[256];
  char arm_str[8] ;
  cpl_frame* nrm_2D=NULL;

  sprintf(arm_str,"%s",xsh_instrument_arm_tostring(inst));
  
  sprintf(file_tag,"%s_%s_%s",rec_prefix,XSH_NORM_ORDER2D,arm_str);
  sprintf(file_name,"%s.fits",file_tag);
  check(nrm_2D=xsh_normalize_spectrum_ord(rect2D,atmext,1,inst,file_tag));
  xsh_add_temporary_file(file_name);


  sprintf(file_tag,"%s_%s_%s",rec_prefix,XSH_FLUX_ORDER2D,arm_str);
  check(*fcal_rect_2D=xsh_util_multiply_by_response_ord(nrm_2D,response,file_tag));
  check(*fcal_2D = xsh_merge_ord(*fcal_rect_2D, inst,mpar,rec_prefix));

cleanup:
  xsh_free_frame(&nrm_2D);
  return cpl_error_get_code();


}

cpl_error_code
xsh_flux_calibrate(cpl_frame* rect2D,
                   cpl_frame* rect1D,
                   cpl_frame* atmext,
                   cpl_frame* response,
                   int mpar,
                   xsh_instrument* inst,
                   const char* rec_prefix,
                   cpl_frame** fcal_rect_2D,
                   cpl_frame** fcal_rect_1D,
                   cpl_frame** fcal_2D,
                   cpl_frame** fcal_1D)
{


  check(xsh_flux_calibrate2D(rect2D,atmext,response,mpar,inst,rec_prefix,
                             fcal_rect_2D,fcal_2D));
  check(xsh_flux_calibrate1D(rect1D,atmext,response,mpar,inst,rec_prefix,
                             fcal_rect_1D,fcal_1D));

 cleanup:

 
  return cpl_error_get_code();
}


cpl_error_code
xsh_ifu_stare_get_calibs(cpl_frameset* calib,
                          xsh_instrument* inst,
                          cpl_frame** spectral_format,
                          cpl_frame** mbias,
                          cpl_frame** mdark,
                          cpl_frame** mflat,
                          cpl_frame** otab_edges,
                          cpl_frame** model_cfg,
                          cpl_frame** bpmap,
                          cpl_frame** wmap,
                          cpl_frame** smap,
                          cpl_frame** ifu_cfg_tab,
                          cpl_frame** ifu_cfg_cor,
                          cpl_frame** wavesol,
                          const char* rec_id,
                          int * recipe_use_model,
                          int pscan)
{

    //cpl_boolean mode_phys;
    //mode_phys=xsh_mode_is_physmod(calib,inst);
    check(*spectral_format = xsh_find_spectral_format( calib, inst));

    XSH_ASSURE_NOT_NULL_MSG(*spectral_format,"Null input spectral format frame");
    check(xsh_instrument_update_from_spectralformat(inst,*spectral_format));

    /* In UVB and VIS mode */

    if (pscan == 0) {
       xsh_msg("pscan=%d",pscan);
        if ( xsh_instrument_get_arm(inst) != XSH_ARM_NIR){
           /* RAWS frameset must have only one file */
           if((*mbias = xsh_find_master_bias( calib, inst)) == NULL) {
              xsh_msg_error("You must give a MASTER_BIAS_ARM frame");
              return CPL_ERROR_DATA_NOT_FOUND;
           }
        }
    }

    /* IFU stuff (physmodel) */
    check(*ifu_cfg_tab = xsh_find_frame_with_tag(calib,XSH_IFU_CFG_TAB,inst));
    check(*ifu_cfg_cor = xsh_find_frame_with_tag(calib,XSH_IFU_CFG_COR,inst));
    check(*spectral_format=xsh_find_spectral_format( calib, inst ) ) ;

    /* one should have either model config frame or wave sol frame */
    check( *model_cfg = xsh_find_frame_with_tag(calib,XSH_MOD_CFG_OPT_AFC, inst));
    if( *model_cfg == NULL) {
        check(*wavesol=xsh_find_frame_with_tag(calib,XSH_WAVE_TAB_AFC, inst));
    }
    /*
     wave_tabs_ifu = xsh_find_wave_tab_ifu( calib, instrument);
     xsh_error_reset();
     */
    /* One of model config and wave tab must be present, but only one ! */
    if ( *model_cfg == NULL){
        xsh_msg("RECIPE USE WAVE SOLUTION");
        *recipe_use_model = FALSE;
    }
    else{
        xsh_msg("RECIPE USE MODEL");
        *recipe_use_model = TRUE;
    }

    if( ( *model_cfg !=NULL) && (*wavesol != NULL) ) {

        xsh_msg_error("You cannot provide both a %s and a %s frame. Decide if you are in poly or physical model mode. We exit",
                        XSH_WAVE_TAB_2D , XSH_MOD_CFG_TAB);
        goto cleanup;
    }

    if(( *model_cfg == NULL) && ( *wavesol == NULL) ) {
        xsh_msg_error("You must provide either a %s or a %s frame",
                        XSH_WAVE_TAB_AFC, XSH_MOD_CFG_TAB);
        goto cleanup;
    }

    if ( ( *mdark = xsh_find_master_dark( calib, inst ) ) == NULL ){
        xsh_msg_warning("Frame %s not provided",XSH_MASTER_DARK);
        xsh_error_reset();
    }

    check( *mflat = xsh_find_master_flat( calib, inst));
    if( *mflat == NULL) {
        xsh_msg_error("Frame %s not provided",XSH_MASTER_FLAT);
        goto cleanup;
    }
    check( *otab_edges = xsh_find_order_tab_edges( calib, inst));
    if( *otab_edges == NULL) {
         xsh_msg_error("Frame %s not provided",XSH_ORDER_TAB_EDGES_IFU);
         goto cleanup;
    }

    /* optional frames */
    check(*bpmap=xsh_check_load_master_bpmap(calib,inst,rec_id));
    check(*wmap = xsh_find_frame_with_tag(calib,XSH_WAVE_MAP,inst));
    check(*smap = xsh_find_frame_with_tag(calib,XSH_SLIT_MAP,inst));

    cleanup:

    return cpl_error_get_code();

}

cpl_error_code
xsh_get_slit_stare_calibs(cpl_frameset* calib, xsh_instrument* instrument,
		cpl_frame** sky_list, cpl_frame** model_cfg,  cpl_frame** qc_sky,
		cpl_frame** sframe_sky_sub_tab, cpl_frame** sky_orders_chunks)
{
	check(*sky_list = xsh_find_frame_with_tag( calib, XSH_SKY_LINE_LIST,
			instrument));
	if ( *model_cfg != NULL){

		if ( *sky_list != NULL){
			/* we compute unbinned THE map to easier plots from QC garching */
			check(*qc_sky=xsh_util_physmod_model_THE_create(*model_cfg,instrument,
					*sky_list,1,1,9,1));
		}
	}

	/* optional frames */
	if ((*sframe_sky_sub_tab = xsh_find_frame_with_tag(calib,XSH_SKY_SUB_BKPTS,
			instrument)) == NULL) {
		xsh_error_reset();
	} else {
		xsh_msg_warning("Data reduction with user defined break points number from file %s",
				cpl_frame_get_filename(*sframe_sky_sub_tab));
	}
	*sky_orders_chunks = xsh_find_frame_with_tag(calib,XSH_SKY_ORDERS_CHUNKS, instrument);

	cleanup:

	return cpl_error_get_code();
}


cpl_error_code
xsh_slit_stare_get_calibs(cpl_frameset* calib,
                          xsh_instrument* instrument,
                          cpl_frame** spectralformat,
                          cpl_frame** mbias,
                          cpl_frame** mdark,
                          cpl_frame** mflat,
                          cpl_frame** otab_edges,
                          cpl_frame** model_cfg,
                          cpl_frame** wave_tab,
                          cpl_frame** sky_list,
                          cpl_frame** sky_orders_chunks,
                          cpl_frame** qc_sky,
                          cpl_frame** bpmap,
                          cpl_frame** sframe_sky_sub_tab,
                          cpl_frame** wmap,
                          cpl_frame** smap,
			  const char* rec_id,
                          int * recipe_use_model,
                          int pscan)
{


   cpl_boolean mode_phys;
   mode_phys=xsh_mode_is_physmod(calib,instrument);
   check(*spectralformat = xsh_find_spectral_format( calib, instrument));

   XSH_ASSURE_NOT_NULL_MSG(*spectralformat,"Null input spectral format frame");
   check(xsh_instrument_update_from_spectralformat(instrument,*spectralformat));

   /* In UVB and VIS mode */
   if (pscan == 0) {
     xsh_msg("pscan=%d",pscan);
      if ( xsh_instrument_get_arm(instrument) != XSH_ARM_NIR){
         /* RAWS frameset must have only one file */
         if((*mbias = xsh_find_master_bias( calib, instrument)) == NULL) {
            xsh_msg_error("You must give a MASTER_BIAS_ARM frame");
            return CPL_ERROR_DATA_NOT_FOUND;
         }
      }
   }

   if((*mdark =  xsh_find_master_dark( calib, instrument))==NULL) {
      xsh_msg_warning("Frame %s not provided",XSH_MASTER_DARK);
      xsh_error_reset();
   }
   if( (*mflat = xsh_find_frame_with_tag(calib,XSH_MASTER_FLAT_SLIT,instrument)) == NULL) {
     xsh_msg_error("Missing required input %s",XSH_GET_TAG_FROM_MODE ( XSH_MASTER_FLAT, instrument));
     cpl_error_set(cpl_func, CPL_ERROR_FILE_NOT_FOUND);
     goto cleanup;
   }
   check( *mflat = xsh_find_master_flat( calib, instrument ));
   check(*otab_edges = xsh_find_order_tab_edges(calib,instrument));

   /* one should have either model config frame or wave sol frame */
   if(mode_phys) {
     if((*model_cfg = xsh_find_frame_with_tag(calib,XSH_MOD_CFG_OPT_AFC,
					      instrument)) == NULL) {
       xsh_error_reset();
       if ((*model_cfg = xsh_find_frame_with_tag(calib,XSH_MOD_CFG_OPT_2D,
						 instrument)) == NULL) {
         xsh_error_reset();

         if ((*model_cfg = xsh_find_frame_with_tag(calib,XSH_MOD_CFG_TAB,
                                                   instrument)) == NULL) {
	   xsh_error_reset();
         } else {
            xsh_msg("RECIPE USE REFERENCE MODEL");
         }
       } else {
            xsh_msg("RECIPE USE OPTIMIZED 2D MODEL");
       }
     } else {
            xsh_msg("RECIPE USE OPTIMIZED AFC MODEL");
     }
     *recipe_use_model = TRUE;
   } else {
      xsh_msg("RECIPE USE WAVE SOLUTION");
      check( *wave_tab = xsh_find_wave_tab( calib, instrument));
      *recipe_use_model = FALSE;
   }
   check(*sky_list = xsh_find_frame_with_tag( calib, XSH_SKY_LINE_LIST,
                                              instrument));
   if ( *model_cfg != NULL){

      if ( *sky_list != NULL){
         /* we compute unbinned THE map to easier plots from QC garching */
         check(*qc_sky=xsh_util_physmod_model_THE_create(*model_cfg,instrument,
                                                         *sky_list,1,1,9,1));
      }
   }

   /* optional frames */
   check(*bpmap=xsh_check_load_master_bpmap(calib,instrument,rec_id));
   if ((*sframe_sky_sub_tab = xsh_find_frame_with_tag(calib,XSH_SKY_SUB_BKPTS,
                                                      instrument)) == NULL) {
      xsh_error_reset();
   } else {
      xsh_msg_warning("Data reduction with user defined break points number from file %s",
                      cpl_frame_get_filename(*sframe_sky_sub_tab));
   }
   *sky_orders_chunks = xsh_find_frame_with_tag(calib,XSH_SKY_ORDERS_CHUNKS, instrument);

   check(*wmap = xsh_find_frame_with_tag(calib,XSH_WAVE_MAP,instrument));
   check(*smap = xsh_find_frame_with_tag(calib,XSH_SLIT_MAP,instrument));

  cleanup:

   return cpl_error_get_code();
}

cpl_error_code
xsh_slit_stare_get_calibs2(cpl_frameset* calib,
		xsh_instrument* instrument,
		cpl_frame** spectralformat,
		cpl_frame** mbias,
		cpl_frame** mdark,
		cpl_frame** mflat,
		cpl_frame** otab_edges,
		cpl_frame** model_cfg,
		cpl_frame** wave_tab,
		cpl_frame** sky_list,
		cpl_frame** sky_orders_chunks,
		cpl_frame** qc_sky,
		cpl_frame** bpmap,
		cpl_frame** sframe_sky_sub_tab,
		cpl_frame** wmap,
		cpl_frame** smap,
		const char* rec_id,
		int * recipe_use_model,
		int pscan)
{


	xsh_get_normal_calibs(calib, instrument, rec_id, pscan, spectralformat, mbias,
			bpmap, otab_edges, mflat);
	//The following should go in xsh_get_normal_calibs()
	check(xsh_instrument_update_from_spectralformat(instrument,*spectralformat));


	if((*mdark =  xsh_find_master_dark( calib, instrument))==NULL) {
		xsh_msg_warning("Frame %s not provided",XSH_MASTER_DARK);
		xsh_error_reset();
	}

	//TODO: extra param, should come from recipe caller.
	int do_computemap=1;
	xsh_get_dispersion_calibs( calib, instrument, do_computemap, model_cfg,
			wave_tab, wmap);
	//TODO: the following two lines should be moved to xsh_get_dispersion_calibs()
	check(*wmap = xsh_find_frame_with_tag(calib,XSH_WAVE_MAP,instrument));
	check(*smap = xsh_find_frame_with_tag(calib,XSH_SLIT_MAP,instrument));

	xsh_get_slit_stare_calibs(calib, instrument, sky_list, model_cfg, qc_sky,
			sframe_sky_sub_tab, sky_orders_chunks);

	cleanup:

	return cpl_error_get_code();
}

cpl_error_code
xsh_slit_offset_get_calibs(cpl_frameset* calib,xsh_instrument* instrument,
		cpl_frame** bpmap,cpl_frame** mbias,
		cpl_frame** mdark, cpl_frame** otab_edges,
		cpl_frame** model_cfg, cpl_frame** wave_tab,
		cpl_frame** mflat, cpl_frame** wmap, cpl_frame** smap,
		cpl_frame** spectral_format,const char* rec_id)
{

	int pscan=0; //extra.
	xsh_get_normal_calibs(calib, instrument, rec_id, pscan, spectral_format,
			mbias, bpmap, otab_edges, mflat);

	/* TODO: Is mdark input really needed? */
	if((*mdark=xsh_find_frame_with_tag(calib,XSH_MASTER_DARK,instrument))==NULL){
		xsh_error_reset();
	}

	//The following need to be defined
	int do_computemap=1;
	xsh_get_dispersion_calibs(calib, instrument, do_computemap, model_cfg,
			wave_tab, wmap);
	//The following is also present in xsh_get_dispersion_calibs
	check( *wmap = xsh_find_wavemap( calib, instrument));
	//The following should be removed to xsh_get_dispersion_calibs
	check( *smap = xsh_find_slitmap( calib, instrument));

	cleanup:
	return cpl_error_get_code();

}

cpl_error_code
xsh_slit_stare_get_params(cpl_parameterlist* parameters,
                          const char* rec_id,
                          int* pre_overscan_corr,
                          xsh_background_param** backg_par,
                          xsh_localize_obj_param** loc_obj_par,
                          xsh_rectify_param** rectify_par,
                          xsh_remove_crh_single_param** crh_single_par,
                          int* sub_sky_nbkpts1,
                          int* do_flatfield,
                          int* sub_sky_nbkpts2,
                          xsh_subtract_sky_single_param** sky_par,
                          int* do_optextract,
                          xsh_opt_extract_param** opt_extract_par,
                          int* generate_sdp_format)
{

   check( *pre_overscan_corr = xsh_parameters_get_int( parameters, rec_id,
                                                       "pre-overscan-corr"));

   check( *backg_par = xsh_parameters_background_get(rec_id,parameters));
 
   check( *loc_obj_par = xsh_parameters_localize_obj_get(rec_id,parameters));
   check( *rectify_par = xsh_parameters_rectify_get(rec_id,parameters));
   check( *crh_single_par = xsh_parameters_remove_crh_single_get(rec_id,parameters));

   check( *sub_sky_nbkpts1 = xsh_parameters_subtract_sky_single_get_first(
             rec_id,parameters));

   check( *sub_sky_nbkpts2 = xsh_parameters_subtract_sky_single_get_second(
             rec_id,parameters));
   check( *sky_par= xsh_parameters_subtract_sky_single_get(rec_id,parameters));

   check( *do_optextract = xsh_parameters_get_boolean( parameters, rec_id,
                                                       "do-optextract"));
   check( *opt_extract_par = xsh_parameters_opt_extract_get(rec_id,parameters));

  if (xsh_parameters_find(parameters, rec_id, "generate-SDP-format") != NULL) {
    check( *generate_sdp_format = xsh_parameters_get_boolean(parameters, rec_id,
                                                       "generate-SDP-format"));
  }

  cleanup:
   return cpl_error_get_code();
}


cpl_error_code
xsh_slit_offset_get_params(cpl_parameterlist* parameters,
                          const char* rec_id,
                          xsh_localize_obj_param** loc_obj_par,
                          xsh_rectify_param** rectify_par,
                          xsh_remove_crh_single_param** crh_single_par,
                          xsh_extract_param**extract_par,
                          xsh_combine_nod_param** combine_nod_param,
                          int* do_flatfield,
                          int* gen_sky,
                          int* generate_sdp_format)
{


   check( *loc_obj_par = xsh_parameters_localize_obj_get(rec_id,parameters));
   check( *rectify_par = xsh_parameters_rectify_get(rec_id,parameters));
   check( *crh_single_par = xsh_parameters_remove_crh_single_get(rec_id,parameters));
   if ( (*rectify_par)->rectify_full_slit == 1 ){

      xsh_msg( "Use Full Slit" ) ;
   }
   else {
      xsh_msg( "Use Max Possible Slit" ) ;
   }

   /*
   check( *opt_kappa = xsh_parameters_optimal_extract_get_kappa(rec_id,parameters));
   */

   check(*extract_par=xsh_parameters_extract_get(rec_id, parameters )) ;

   check(*combine_nod_param = xsh_parameters_combine_nod_get(rec_id,parameters )) ;


   check( *gen_sky = xsh_parameters_get_boolean( parameters, rec_id,
                                                 "gen-sky"));

  if (xsh_parameters_find(parameters, rec_id, "generate-SDP-format") != NULL) {
    check( *generate_sdp_format = xsh_parameters_get_boolean(parameters, rec_id,
                                                       "generate-SDP-format"));
  }

  cleanup:
   return cpl_error_get_code();

}

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

/**
  @brief correct CRH and sky lines (1st iteration)
  @param[in] loc_obj_par parameters to localise the object
  @param[in] crh_single_par parameters to do CRH rejection  TO BE REMOVED
  @param[in] rectify_par parameters to do order rectification
  @param[in] do_sub_sky is sky subtraction to be done? 1/0: yes/no
  @param[in] rec_prefix recipe id
  @param[in] rmbkg input frame (inter-order background subtracted)
  @param[in] order_tab_edges order edges table
  @param[in] slitmap slitmap frame
  @param[in] wavemap wavemap frame
  @param[in] model_config model configuration frame
  @param[in] single_frame_sky_sub_tab reference frame with sky line positions
  @param[in] instrument structure with information on the instrument (arm)
  @param[in] sub_sky_nbkpts1 number of sky subtraction points (1st iteration)
  @param[in] sky_par sky subtraction parameters
  @param[out] sky output sky frame (DRL format)
  @param[out] sky_eso output sky frame (ESO format)
  @param[out] sky_ima output sky image used for QC    (NEEDED??)
  @param[in] wave_tab wavelength table (used during order rectification)
  @param[in] disp_tab wavelength table (used during rectif to compute Jakobian)
  @param[in] spectral_format input spectral format table (used during rectification)
  @param[in] nb_raw_frames number of input fraw frames (used to make a check)
  @param[in] loc_table computed object localisation table
  @param[out] clean sky subtracted frame (after 1st iteration)
  @param[out] clean_obj input object frame (cleaned by CRH. Now same as rmbkg. NOT NEEDED)
  @param[out] clean_tmp Switch to erase temporary products

 */


cpl_error_code
xsh_slit_stare_correct_crh_and_sky(xsh_localize_obj_param * loc_obj_par,
                                   xsh_remove_crh_single_param* crh_single_par,
                                   xsh_rectify_param* rectify_par,
                                   int do_sub_sky,
                                   const char* rec_prefix,
                                   cpl_frame* rmbkg,
                                   cpl_frame* order_tab_edges, 
                                   cpl_frame* slitmap, 
                                   cpl_frame* wavemap,
                                   cpl_frame* sky_map,
                                   cpl_frame* model_config,
                                   cpl_frame* single_frame_sky_sub_tab,
                                   xsh_instrument* instrument,
                                   int sub_sky_nbkpts1, 
                                   xsh_subtract_sky_single_param* sky_par,
                                   cpl_frame* ref_sky_list,
                                   cpl_frame* sky_orders_chunks,
                                   cpl_frame** sky,
                                   cpl_frame** sky_eso,
                                   cpl_frame** sky_ima,
                                   cpl_frame* wave_tab,
                                   cpl_frame* disp_tab,
                                   cpl_frame* spectral_format,
                                   int nb_raw_frames,
                                   cpl_frame** loc_table,
                                   cpl_frame** clean,
                                   cpl_frame** clean_obj,const int clean_tmp)
{

    char sky_tag[256];
    char sky_name[256];
    char rec_name[256];
    cpl_frame * sub_sky = NULL ; /**< Output of xsh_subtract_sky_single */
    cpl_frame * rect = NULL ;    /**< Output of xsh_rectfiy */

    if( (loc_obj_par->method != LOC_MANUAL_METHOD) ){
                  //  || (nb_raw_frames == 1 && crh_single_par->nb_iter > 0)){

        xsh_msg("Preliminary sky subtraction for CRH single or automatic localization");
        xsh_msg("Sky will be put back later");

        sprintf(sky_tag,"%s_TMPSKY",rec_prefix);
        sprintf(sky_name,"%s.fits",sky_tag);

        if(do_sub_sky) {
            /* TODO AMO: aded frame for DEBUG */
            xsh_msg("rmbkg=%p",rmbkg);
            check(xsh_frame_image_save(rmbkg,"rmbkg.fits"));
            xsh_msg("instrument=%p",instrument);
            check( sub_sky = xsh_check_subtract_sky_single( CPL_TRUE, rmbkg,
                            order_tab_edges, slitmap, wavemap, NULL,
                            single_frame_sky_sub_tab, instrument, sub_sky_nbkpts1,
                            sky_par,ref_sky_list, sky_orders_chunks,sky, sky_eso, sky_ima, sky_tag,clean_tmp));
            xsh_add_temporary_file(sky_name);

            /* TODO AMO: aded frame for DEBUG */
            xsh_frame_image_save(sub_sky,"sub_sky.fits");
            //exit(0);

        } else {
            sub_sky = cpl_frame_duplicate(rmbkg);
            xsh_add_temporary_file(sky_name);
        }

        if( loc_obj_par->method != LOC_MANUAL_METHOD){
            xsh_msg("Localize auto");
            sprintf(rec_name,"%s_%s_%s.fits",
                    rec_prefix,XSH_ORDER2D,
                    xsh_instrument_arm_tostring(instrument));

            check( rect = xsh_rectify( sub_sky, order_tab_edges,
                            wave_tab, model_config,
                            instrument, rectify_par,
                            spectral_format, disp_tab,
                            rec_name, NULL, NULL,rec_prefix));

            check( *loc_table = xsh_localize_obj( rect, NULL, instrument,
                            loc_obj_par, NULL, NULL));
            xsh_free_frame( &rect);
        }
        else{
            check( *loc_table = xsh_localize_obj( NULL, NULL,
                            instrument, loc_obj_par, NULL, NULL));
        }

        /* NB Remove COSMICS single temporarily dis-activated for Daniel
          check( *clean = xsh_check_remove_crh_single( nb_raw_frames, sub_sky,
                          crh_single_par, instrument, rec_prefix));
         */
        *clean = cpl_frame_duplicate(sub_sky);

        if(clean_tmp) {
            xsh_add_temporary_file(cpl_frame_get_filename(*clean));
        }
        if(do_sub_sky) {
            check( *clean_obj = xsh_add_sky_model( *clean, *sky_ima,
                            instrument, rec_prefix));
        } else {
            *clean_obj=cpl_frame_duplicate(*clean);
        }

        xsh_free_frame( &sub_sky);
        xsh_free_frame( sky);
        xsh_free_frame( sky_eso);
        xsh_free_frame( sky_ima);
    }
    else {
        /* LOcalize manual && no CRH SINGLE */
        check( *clean_obj=cpl_frame_duplicate(rmbkg));
        check( *loc_table = xsh_localize_obj( NULL, NULL,
                        instrument, loc_obj_par, NULL, NULL));
    }

    cleanup:

    xsh_free_frame(&sub_sky) ;
    xsh_free_frame(&rect) ;

    return cpl_error_get_code();

}


cpl_error_code
xsh_slit_stare_get_maps(cpl_frameset* calib,
                        int do_compute_map,int recipe_use_model,
                        const char* rec_prefix,xsh_instrument* instrument,
                        cpl_frame* model_config_frame,cpl_frame* crhm_frame,
                        cpl_frame* disp_tab_frame, cpl_frame* order_tab_edges,
                        cpl_frame** wavemap_frame, cpl_frame** slitmap_frame)
{
   char wave_map_tag[256];
   char slit_map_tag[256];
   int found_temp=1;
   if ( do_compute_map){
      if (recipe_use_model){
         sprintf(wave_map_tag,"%s_%s_%s",rec_prefix,XSH_WAVE_MAP_MODEL,
                 xsh_instrument_arm_tostring( instrument ));
         sprintf(slit_map_tag,"%s_%s_%s",rec_prefix,XSH_SLIT_MAP_MODEL,
                 xsh_instrument_arm_tostring( instrument ));
      
         check(xsh_model_temperature_update_frame(&model_config_frame,crhm_frame,
                                                  instrument,&found_temp));
    
         check( xsh_create_model_map( model_config_frame, instrument,
                                      wave_map_tag,slit_map_tag, 
                                      wavemap_frame, slitmap_frame,0));
      }
      else{
         xsh_msg("Compute the wave map and the slit map");
         check( xsh_create_map( disp_tab_frame, order_tab_edges,
                                crhm_frame, instrument, 
                                wavemap_frame, slitmap_frame,
                                rec_prefix));
      }
   }
   else {
      xsh_msg( "Get the wave map and the slit map from sof" ) ;
      check( *slitmap_frame = xsh_find_slitmap(calib, instrument));
      check( *wavemap_frame = xsh_find_wavemap(calib, instrument));
   }

  cleanup:
   return cpl_error_get_code();
}


cpl_error_code
xsh_scired_util_spectra_flux_calibrate(cpl_frame* res2D,cpl_frame* res1D,
                                       cpl_frame* response,cpl_frame* atmext,
                                       xsh_instrument* inst,
                                       const char* prefix,
                                       cpl_frame** fluxcal_2D,
                                       cpl_frame** fluxcal_1D)
{
   char  file_tag[40];
   cpl_frame* nrm_1D=NULL;
   cpl_frame* nrm_2D=NULL;

   sprintf(file_tag,"%s_NORM2D_%s",prefix,xsh_instrument_arm_tostring(inst));
   check(nrm_2D=xsh_normalize_spectrum(res2D,atmext,0,inst,file_tag));
   sprintf(file_tag,"%s_FLUXCAL2D_%s",prefix,xsh_instrument_arm_tostring(inst));
   check(*fluxcal_2D=xsh_util_multiply_by_response(nrm_2D,response,file_tag));
   sprintf(file_tag,"%s_NORM1D_%s",prefix,xsh_instrument_arm_tostring(inst));
   check(nrm_1D=xsh_normalize_spectrum(res1D,atmext,0,inst,file_tag));
   sprintf(file_tag,"%s_FLUXCAL1D_%s",prefix,xsh_instrument_arm_tostring(inst));
   check(*fluxcal_1D=xsh_util_multiply_by_response(nrm_1D,response,file_tag));

  cleanup:
   xsh_free_frame(&nrm_1D);
   xsh_free_frame(&nrm_2D);

   return cpl_error_get_code();

}


cpl_frame* xsh_compute_efficiency(cpl_frame* mer1D, cpl_frame* std_cat, 
				  cpl_frame* atm_ext, cpl_frame* high_abs_win, 
				       xsh_instrument* instr)
{
    
  cpl_frame* eff=NULL;

  if(NULL == (eff=xsh_efficiency_compute(mer1D,std_cat,atm_ext,high_abs_win,instr))) {
    xsh_msg_error("An error occurred during efficiency computation");
    xsh_msg_error("The recipe recovers without efficiency product generation");
    cpl_error_reset();
  } else {
    check(xsh_frame_table_monitor_flux_qc(eff,"WAVELENGTH","EFF","EFF",instr));
  }

 cleanup:
 return eff;
}

static cpl_error_code
xsh_get_central_xy(cpl_frame* order_tab_edges,xsh_instrument* instrument, int* xcen, int* ycen)
{

  const char* name = NULL;
  cpl_table* tab = NULL;
  int ord_min = 0;
  int ord_max = 0;
  int ord_avg = 0;
  int next = 0;
  int status=0;

  cpl_table* ext = NULL;

  XSH_ASSURE_NOT_NULL_MSG(order_tab_edges,"Null input order tab edges");

  name = cpl_frame_get_filename(order_tab_edges);
  tab = cpl_table_load(name, 2, 0);

  ord_min = cpl_table_get_column_min(tab, "ORDER");
  ord_max = cpl_table_get_column_max(tab, "ORDER");
  ord_avg = 0.5 * (ord_min + ord_max);

  next = cpl_table_and_selected_int(tab, "ORDER", CPL_EQUAL_TO, ord_avg);
  ext = cpl_table_extract_selected(tab);
  xsh_free_table(&tab);

  *xcen = (int) cpl_table_get_double(ext, "CENTER_X", next / 2, &status);
  *xcen /= instrument->binx;

  *ycen = (int) cpl_table_get_double(ext, "CENTER_Y", next / 2, &status);
  *ycen /= instrument->biny;

  cleanup:
    xsh_free_table(&tab);
    xsh_free_table(&ext);
    return cpl_error_get_code();
}

static cpl_error_code xsh_frame_image_get_step(cpl_frame* frm_ima,
    const int xcen, const int ycen, const int direction, double* dif) {

  int xmin = 0;
  int xmax = 0;

  int ymin = 0;
  int ymax = 0;

  const char* name = NULL;
  cpl_image* map_ima = NULL;
  int nx = 0;
  double* map = NULL;
  double fmin=0;
  double fmax=0;

  name = cpl_frame_get_filename(frm_ima);
  map_ima = cpl_image_load(name, CPL_TYPE_DOUBLE, 0, 0);
  nx = cpl_image_get_size_x(map_ima);
  map = cpl_image_get_data_double(map_ima);


  xmin = xcen - 1;
  xmax = xcen + 1;

  ymin = ycen - 1;
  ymax = ycen + 1;


  if(1==direction) {
     ymin = ycen - 1;
     ymax = ycen + 1;

     fmin = map[nx * ymin + xcen];
     fmax = map[nx * ymax + xcen];
  } else {
     xmin = xcen - 1;
     xmax = xcen + 1;

     fmin = map[nx * ycen + xmin];
     fmax = map[nx * ycen + xmax];
  }

  *dif = fabs(0.5 * (fmax - fmin));

  xsh_free_image(&map_ima);

  return cpl_error_get_code();

}


static cpl_error_code xsh_plist_set_spat_accuracy(cpl_propertylist* header,
    const double srms, const double serr, const double sys_err) {
  cpl_propertylist_insert_after_double(header, XSH_CUNIT1,XSH_SPATRMS, srms);
  cpl_propertylist_set_comment(header, XSH_SPATRMS,
      XSH_SPATRMS_C);
  cpl_propertylist_insert_after_double(header, XSH_SPATRMS, XSH_CRDER2, serr);
  cpl_propertylist_set_comment(header, XSH_CRDER2, XSH_CRDER2_C);
  cpl_propertylist_insert_after_double(header, XSH_CRDER2, XSH_CSYER2, sys_err);
  cpl_propertylist_set_comment(header, XSH_CSYER2, XSH_CSYER2_C);
  cpl_propertylist_insert_after_string(header, XSH_CSYER2, XSH_CUNIT2, "arcsec");
  cpl_propertylist_set_comment(header, XSH_CUNIT2, XSH_CUNIT2_C);

  return cpl_error_get_code();
}

static cpl_error_code xsh_plist_set_wave_accuracy(cpl_propertylist* header,
    const double wrms, const double werr, const double sys_err) {

  if (wrms > 0) {  /* Only write valid LAMRMS values. */
    cpl_propertylist_insert_after_double(header, XSH_LAMNLIN, XSH_LAMRMS, wrms);
    cpl_propertylist_set_comment(header, XSH_LAMRMS, XSH_LAMRMS_C);
    cpl_propertylist_insert_after_double(header, XSH_LAMRMS, XSH_CRDER1, werr);
  } else {
    cpl_propertylist_insert_after_double(header, XSH_LAMNLIN, XSH_CRDER1, werr);
  }
  cpl_propertylist_set_comment(header, XSH_CRDER1, XSH_CRDER1_C);
  cpl_propertylist_insert_after_double(header, XSH_CRDER1, XSH_CSYER1, sys_err);
  cpl_propertylist_set_comment(header, XSH_CSYER1, XSH_CSYER1_C);
  cpl_propertylist_insert_after_string(header, XSH_CSYER1, XSH_CUNIT1, "nm");
  cpl_propertylist_set_comment(header, XSH_CUNIT1, XSH_CUNIT1_C);

  return cpl_error_get_code();
}

double
xsh_get_systematic_wave_accuracy(xsh_instrument* instrument)
{
    double csyer1=0.02;
    if (xsh_instrument_get_arm(instrument) == XSH_ARM_UVB) {
        csyer1 = 0.03; /* nm */
    }
    else if (xsh_instrument_get_arm(instrument) == XSH_ARM_VIS) {
        csyer1 = 0.02; /* nm */
    }
    else if (xsh_instrument_get_arm(instrument) == XSH_ARM_NIR) {
        csyer1 = 0.004; /* nm */
    }
    return csyer1;
}

double
xsh_get_systematic_spatial_accuracy(xsh_instrument* instrument)
{
    double csyer2=0.16;
    if (xsh_instrument_get_arm(instrument) == XSH_ARM_UVB) {
        csyer2 = 0.17; /* arcsecs */
    }
    else if (xsh_instrument_get_arm(instrument) == XSH_ARM_VIS) {
        csyer2 = 0.16; /* arcsecs */
    }
    else if (xsh_instrument_get_arm(instrument) == XSH_ARM_NIR) {
        csyer2 = 0.25; /* arcsecs */
    }
    return csyer2;
}

cpl_error_code
xsh_compute_resampling_accuracy(cpl_frame* wavemap,
				cpl_frame* slitmap,
				cpl_frame* order_tab_edges,
				cpl_frame* model_config,
				cpl_frame* science,
				xsh_instrument* instrument) {

  cpl_propertylist* plist=NULL;
  const char* name=NULL;
  const char* tag=NULL;

  double rms_x=0;
  double rms_y=0;
  cpl_table* tab=NULL;
  cpl_table* ext=NULL;

  xsh_pre* pre=NULL;

  int xcen=0;
  int ycen=0;

  double wdif;
  double sdif;

  cpl_image* wmap_ima=NULL;
  cpl_image* smap_ima=NULL;
  cpl_frame* frm_tmp=NULL;
  xsh_spectrum* s=NULL;
  cpl_image* ima=NULL;
  cpl_propertylist* phead=NULL;
  cpl_propertylist* xhead=NULL;
  cpl_image* xima=NULL;

  double wrms=0;
  double srms=0;
  double werr=0;
  double serr=0;
  int nline=1;
  //int nbext=0;
  double csyer1=0;
  double csyer2=1; /* pix */

  XSH_ASSURE_NOT_NULL_MSG(wavemap,"Null input wavemap");
  XSH_ASSURE_NOT_NULL_MSG(slitmap,"Null input wavemap");
  XSH_ASSURE_NOT_NULL_MSG(order_tab_edges,"Null input order tab edges");
  XSH_ASSURE_NOT_NULL_MSG(model_config,"Null input model config");
  XSH_ASSURE_NOT_NULL_MSG(science,"Null input sci frame");
  XSH_ASSURE_NOT_NULL_MSG(instrument,"Null input instrument structure");
  csyer1=xsh_get_systematic_wave_accuracy(instrument);
  check(xsh_get_central_xy(order_tab_edges,instrument,&xcen, &ycen));
  check(xsh_frame_image_get_step(wavemap,xcen,ycen,1,&wdif));
  check(xsh_frame_image_get_step(slitmap,xcen,ycen,0,&sdif));



  name=cpl_frame_get_filename(model_config);
  plist=cpl_propertylist_load(name,0);
  if(cpl_propertylist_has(plist,XSH_QC_MODEL_ANNEAL_RESX_RMS) ){
     check(rms_x=cpl_propertylist_get_double(plist,XSH_QC_MODEL_ANNEAL_RESX_RMS));
  } else {
     xsh_msg_warning("Key %s not found %s, %s will be set to 0",
                     XSH_QC_MODEL_ANNEAL_RESX_RMS,XSH_LAMRMS,XSH_CRDER1);
  }

  if(cpl_propertylist_has(plist,XSH_QC_MODEL_ANNEAL_RESY_RMS) ){
     check(rms_y=cpl_propertylist_get_double(plist,XSH_QC_MODEL_ANNEAL_RESY_RMS));
  } else {
     xsh_msg_warning("Key %s not found %s, %s will be set to 0",
                     XSH_QC_MODEL_ANNEAL_RESY_RMS,XSH_SPATRMS,XSH_CRDER2);
  }

  if(cpl_propertylist_has(plist,XSH_QC_MODEL_NDAT) ){
     nline=cpl_propertylist_get_int(plist,XSH_QC_MODEL_NDAT);
  }
  xsh_free_propertylist(&plist);

  srms=rms_x*sdif;
  wrms=rms_y*wdif;
  serr=srms/sqrt(nline);
  werr=wrms/sqrt(nline);
  name=cpl_frame_get_filename(science);
  tag=cpl_frame_get_tag(science);
  //xsh_msg("process frame %s %s",name,tag);
  //xsh_msg("wdif=%g wrms=%g werr=%g sdif=%g srms=%g serr=%g",wdif,wrms,werr,sdif,srms,serr);

  if(strstr(tag,"MERGE2D")!=NULL) {
    //xsh_msg("MERGE2D");
     check(s=xsh_spectrum_load(science));

     cpl_propertylist_insert_after_int(s->flux_header,"DATE",XSH_LAMNLIN,nline);
     cpl_propertylist_set_comment(s->flux_header,XSH_LAMNLIN,XSH_LAMNLIN_C);
     check(csyer2=xsh_get_systematic_spatial_accuracy(instrument));
     check(xsh_plist_set_wave_accuracy(s->flux_header,wrms,werr,csyer1));
     check(xsh_plist_set_spat_accuracy(s->flux_header,srms,serr,csyer2));


     frm_tmp=xsh_spectrum_save(s,name,tag);

  } else if(strstr(tag,"ORDER2D")!=NULL) {

    //xsh_msg("ORDER2D");


     int nbext=0;
     int i=0;
     char cmd[256];
     const char *tname = "tmp_ima.fits";


     nbext = cpl_frame_get_nextensions( science);
     check(phead = cpl_propertylist_load( name, 0 ));
     ima=cpl_image_load(name,CPL_TYPE_FLOAT,0,0);

     sprintf(cmd,"mv  %s %s",name,tname);
     system(cmd);
     xsh_add_temporary_file("tmp_ima.fits");

     cpl_propertylist_insert_after_int(phead,"DATE",XSH_LAMNLIN,nline);
     cpl_propertylist_set_comment(phead,XSH_LAMNLIN,XSH_LAMNLIN_C);
     check(csyer2=xsh_get_systematic_spatial_accuracy(instrument));
     check(xsh_plist_set_wave_accuracy(phead,wrms,werr,csyer1));
     check(xsh_plist_set_spat_accuracy(phead,srms,serr,csyer2));


      check(cpl_image_save(ima, name, CPL_BPP_IEEE_FLOAT,
             phead,CPL_IO_DEFAULT));
      for( i = 0 ; i<=nbext ; i++ ) {
        int extension ;
        xsh_free_image( &xima) ;
        xsh_free_propertylist( &xhead) ;
        check(xima = cpl_image_load( tname, CPL_TYPE_FLOAT, 0,i ));
        check(xhead = cpl_propertylist_load( tname ,i));
        if ( i == 0 ) {
          extension = CPL_IO_DEFAULT ;
          check(cpl_image_save(xima, name, CPL_BPP_IEEE_FLOAT,
                 phead,extension));
        }
        else {
          extension = CPL_IO_EXTEND ;
      check(cpl_image_save(xima, name, CPL_BPP_IEEE_FLOAT,xhead,extension));
        }
      }
      sprintf(cmd,"rm  tmp_ima.fits");
      system(cmd);
  } 
  //xsh_msg("processed frame %s",tag);

 cleanup:

  xsh_free_image( &xima) ;
  xsh_free_image( &ima) ;
  xsh_free_propertylist( &xhead) ;
  xsh_free_propertylist( &phead) ;
  xsh_free_frame(&frm_tmp);
  xsh_pre_free(&pre);
  xsh_free_table(&tab);
  xsh_free_table(&ext);
  xsh_free_image(&wmap_ima);
  xsh_free_image(&smap_ima);
  xsh_free_propertylist(&plist);
  xsh_spectrum_free(&s);

  return cpl_error_get_code();

}


cpl_error_code
xsh_compute_wavelength_resampling_accuracy(cpl_frame* wavemap,
        cpl_frame* order_tab_edges,
        cpl_frame* model_config,
        cpl_frame* science,
        xsh_instrument* instrument) {

  cpl_propertylist* plist=NULL;
  cpl_frame* frm_tmp=NULL;
  const char* name=NULL;
  const char* tag=NULL;

  double rms_y=0;
  cpl_table* tab=NULL;
  cpl_table* ext=NULL;

  xsh_pre* pre=NULL;
  //xsh_rec_list * rec_list = NULL ;
  int xcen=0;
  int ycen=0;

  double wdif;

  cpl_image* wmap_ima=NULL;
  xsh_spectrum* s=NULL;
  cpl_vector* vec=NULL;
  double wrms=0;
  double werr=0;
  int nline=1;
  cpl_propertylist* xhead=NULL;
  cpl_vector* xvec=NULL;
  cpl_table* xtab=NULL;
  cpl_propertylist* phead=NULL;
  double csyer1=0;

  XSH_ASSURE_NOT_NULL_MSG(wavemap,"Null input wavemap");
  XSH_ASSURE_NOT_NULL_MSG(order_tab_edges,"Null input order tab edges");
  XSH_ASSURE_NOT_NULL_MSG(model_config,"Null input model config");
  XSH_ASSURE_NOT_NULL_MSG(science,"Null input sci frame");
  XSH_ASSURE_NOT_NULL_MSG(instrument,"Null input instrument structure");

  csyer1=xsh_get_systematic_wave_accuracy(instrument);

  check(xsh_get_central_xy(order_tab_edges,instrument,&xcen, &ycen));
  check(xsh_frame_image_get_step(wavemap,xcen,ycen,1,&wdif));

  name=cpl_frame_get_filename(model_config);
  plist=cpl_propertylist_load(name,0);

  if (cpl_propertylist_has(plist, XSH_QC_MODEL_ANNEAL_RESY_RMS)) {
    check(
        rms_y = cpl_propertylist_get_double(plist,
            XSH_QC_MODEL_ANNEAL_RESY_RMS));
  } else {
    xsh_msg_warning("Key %s not found %s, %s will be set to 0",
        XSH_QC_MODEL_ANNEAL_RESY_RMS, XSH_SPATRMS, XSH_CRDER2);
  }

  if(cpl_propertylist_has(plist,XSH_QC_MODEL_NDAT) ){
     nline=cpl_propertylist_get_int(plist,XSH_QC_MODEL_NDAT);
  }
  xsh_free_propertylist(&plist);

  wrms=rms_y*wdif;
  werr=wrms/sqrt(nline);
  name=cpl_frame_get_filename(science);
  tag=cpl_frame_get_tag(science);

  xsh_msg("process frame %s %s",name,tag);
  if(strstr(tag,"MERGE1D")!=NULL) {
     xsh_msg("MERGE1D");
    check(s=xsh_spectrum_load(science));
    cpl_propertylist_insert_after_int(s->flux_header,"DATE",XSH_LAMNLIN,nline);
    cpl_propertylist_set_comment(s->flux_header,XSH_LAMNLIN,XSH_LAMNLIN_C);
    check(xsh_plist_set_wave_accuracy(s->flux_header,wrms,werr,csyer1));


    frm_tmp=xsh_spectrum_save(s,name,tag);

  } else if( strstr(tag,"ORDER1D")!=NULL ) {
	  xsh_msg("ORDER1D");
	  int nbext=0;
	  int i=0;
	  char cmd[256];
	  const char *tname = "tmp_ima.fits";
	  nbext = cpl_frame_get_nextensions( science);
	  check(phead = cpl_propertylist_load( name, 0 ));
	  //ima=cpl_image_load(name,CPL_TYPE_FLOAT,0,0);
	  vec=cpl_vector_load(name,0);

	  sprintf(cmd,"mv  %s %s",name,tname);
	  system(cmd);
	  xsh_add_temporary_file("tmp_ima.fits");
	  cpl_propertylist_insert_after_int(phead,"DATE",XSH_LAMNLIN,nline);
	  cpl_propertylist_set_comment(phead,XSH_LAMNLIN,XSH_LAMNLIN_C);
	  check(xsh_plist_set_wave_accuracy(phead,wrms,werr,csyer1));

	  check(cpl_vector_save(vec, name, CPL_BPP_IEEE_FLOAT,
			  phead,CPL_IO_DEFAULT));
	  for( i = 0 ; i<=nbext ; i++ ) {
		  int extension ;
		  xsh_free_vector( &xvec) ;
		  xsh_free_propertylist( &xhead) ;
		  check(xvec = cpl_vector_load( tname,i ));
		  check(xhead = cpl_propertylist_load( tname ,i));
		  if ( i == 0 ) {
			  extension = CPL_IO_DEFAULT ;
			  check(cpl_vector_save(xvec, name, CPL_BPP_IEEE_FLOAT,
					  phead,extension));
		  }
		  else {
			  extension = CPL_IO_EXTEND ;
			  check(cpl_vector_save(xvec, name, CPL_BPP_IEEE_FLOAT,xhead,extension));
		  }
	  }
	  sprintf(cmd,"rm  tmp_ima.fits");
	  system(cmd);

  } else if(strstr(tag,"SKY_ORD1D")!=NULL) {
	  xsh_msg("SKY_ORD1D");

	  int nbext=0;
	  int i=0;
	  char cmd[256];
	  const char *tname = "tmp_tab.fits";
	  nbext = cpl_frame_get_nextensions( science);
	  check(phead = cpl_propertylist_load( name, 0 ));
      xsh_msg("name=%s",name);
	  check(tab=cpl_table_load(name,1,0));

	  sprintf(cmd,"mv  %s %s",name,tname);
	  system(cmd);
	  xsh_add_temporary_file(tname);
	  cpl_propertylist_insert_after_int(phead,"DATE",XSH_LAMNLIN,nline);
	  cpl_propertylist_set_comment(phead,XSH_LAMNLIN,XSH_LAMNLIN_C);
	  check(xsh_plist_set_wave_accuracy(phead,wrms,werr,csyer1));

	  check(cpl_table_save(tab, phead, NULL, name, CPL_IO_DEFAULT));
	  for( i = 0 ; i<=nbext ; i++ ) {
		  int extension ;
		  xsh_free_table( &xtab) ;
		  xsh_free_propertylist( &xhead) ;
		  check(xtab = cpl_table_load( tname,1, i ));
		  check(xhead = cpl_propertylist_load( tname ,i));
		  if ( i == 0 ) {
			  extension = CPL_IO_DEFAULT ;
			  check(cpl_table_save(xtab, phead, NULL, name, extension));
		  }
		  else {
			  extension = CPL_IO_EXTEND ;
			  check(cpl_table_save(xtab, phead, NULL, name, extension));

		  }
	  }
	  sprintf(cmd,"rm  tmp_tab.fits");
	  system(cmd);

  }
  xsh_msg("processed frame %s",tag);
 cleanup:
  xsh_free_frame(&frm_tmp);
  xsh_free_propertylist( &phead) ;
  xsh_free_propertylist( &xhead) ;
  xsh_free_vector( &xvec) ;
  xsh_free_vector( &vec) ;
  xsh_pre_free(&pre);
  xsh_free_table(&tab);
  xsh_free_table(&ext);
  xsh_free_image(&wmap_ima);
  xsh_free_propertylist(&plist);
  xsh_spectrum_free(&s);
  xsh_print_rec_status(0);
  return cpl_error_get_code();

}


/*****************************************************************************/
/**
  @brief
    Generates a new frameset with each frame CRH-sigle rejected from input frameset
 @param[in] raws
   The input Frameset
   @param[in] crh_single_par
   Parameters for remove crh single
 @param[in] instrument
   Pointer to instrument description

 @return
   The input frameset after removal of Cosmics
*/
/*****************************************************************************/
cpl_frameset*
xsh_frameset_crh_single(cpl_frameset* raws,
                        xsh_remove_crh_single_param * crh_single_par,
                        cpl_frame* sky_map_frm,
    xsh_instrument* instrument,const char* prefix,const char* spec)
{
/* remove crh on frame */
 cpl_frameset* clean=NULL;
 cpl_frame* frm=NULL;
 int nraws=0;
 int i=0;
 char ftag[256];
 char fname[256];
 char  arm_str[16] ;
 cpl_frame * rm_crh = NULL ;
 cpl_image * sky_map_ima = NULL;
 cpl_mask * sky_map_msk = NULL;
 //cpl_frameset_dump(raws,stdout);

 if( sky_map_frm != NULL ) {
   sky_map_ima = cpl_image_load(cpl_frame_get_filename(sky_map_frm),CPL_TYPE_FLOAT,0,0);
   sky_map_msk=cpl_mask_threshold_image_create(sky_map_ima,0.1,1.1);
 }
 sprintf( arm_str, "%s",  xsh_instrument_arm_tostring(instrument) ) ;
 nraws=cpl_frameset_get_size(raws);
 check( clean = cpl_frameset_new() ) ;
 /* AMO: Don't do CRH single on a raw frame, need to be done on a sky corrected one */
 if ( crh_single_par->nb_iter > 0 ) {
    xsh_msg( "Detect crh (single frame) as removecrhsingle_niter > 0" ) ;
    for ( i = 0 ; i < nraws ; i++ ) {

      frm = cpl_frameset_get_frame( raws, i )  ;
      sprintf(ftag,"%s_%s_NO_CRH_%s_%d",prefix,spec,arm_str,i) ;
      sprintf(fname,"%s.fits",ftag) ;

      rm_crh = xsh_remove_crh_single( frm,instrument,sky_map_msk,crh_single_par,ftag ) ;
      xsh_add_temporary_file(fname);
      cpl_frameset_insert( clean, rm_crh ) ;
    }
  } else {
    xsh_msg_warning( "Skip Remove crh (single frame) on not sky corrected frame" ) ;
    clean=cpl_frameset_duplicate(raws);
  }
 if( sky_map_frm != NULL ) {
     xsh_free_image(&sky_map_ima);
     xsh_free_mask(&sky_map_msk);
 }
cleanup:
 return clean;
}


/*****************************************************************************/
/**
  @brief
    Generates a new frameset with each frame mflat divided input frameset
 @param[in] raws
   The input Frameset
   @param[in] mflat
   master flat
 @param[in] instrument
   Pointer to instrument description

 @return
   A new frameset resulting from the division of each input frame from the input
   frameset by master flat
*/
/*****************************************************************************/
cpl_frameset*
xsh_frameset_mflat_divide(cpl_frameset* input, cpl_frame* mflat,
    xsh_instrument* instrument) {

  int nraw = 0;
  int i = 0;

  cpl_frame * divided = NULL;
  cpl_frame * frm = NULL;
  char  arm_str[16] ;
  char ftag[256];
  char fname[256];

  cpl_frameset* output = NULL;

  xsh_msg("apply flat field");

  nraw = cpl_frameset_get_size(input);
  output = cpl_frameset_new();
  sprintf( arm_str, "%s",  xsh_instrument_arm_tostring(instrument) ) ;
  for (i = 0; i < nraw; i++) {
    frm = cpl_frameset_get_frame(input, i);

    sprintf(ftag, "FF_%d_SLIT_OFFSET_%s", i,arm_str);
    sprintf(fname, "%s.fits", ftag);
    
    /* the following function creates a new frame: output is a new frameset.
     * For this reason there is no need to duplicate the frame when we insert
     * it in the output frameset. In the end we need to remember to cleanup
     * the output frameset.
     */
    divided = xsh_divide_flat( frm,mflat, ftag, instrument );
    xsh_add_temporary_file(fname);
    cpl_frameset_insert(output, divided );

  }

  return output;
}

/**@}*/
