/*                                                                            *
 *   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 Sotware 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: 2012-12-20 15:43:22 $
 * $Revision: 1.60 $
 *
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/*----------------------------------------------------------------------------*/
/**
 * @defgroup xsh_scired_ifu_offset   xsh_scired_ifu_offset
 * @ingroup recipes
 *
 * This recipe ...
 * See man-page for details.
 */
/*----------------------------------------------------------------------------*/
/**@{*/

/*-----------------------------------------------------------------------------
  Includes
  ----------------------------------------------------------------------------*/

/* DRL steps */

/* Error handling */
#include <xsh_error.h>
/* Utility fonctions */
#include <xsh_utils.h>
#include <xsh_msg.h>
/* DFS functions */
#include <xsh_dfs.h>
#include <xsh_pfits.h>
#include <xsh_data_spectrum1D.h>
#include <xsh_utils_image.h>
#include <xsh_model_io.h>
#include <xsh_model_utils.h>
#include <xsh_utils_ifu.h>
#include <xsh_utils_scired_slit.h>
#include <xsh_model_arm_constants.h>
/* DRL functions */
#include <xsh_drl.h>
#include <xsh_drl_check.h>
/* Library */
#include <cpl.h>

/*-----------------------------------------------------------------------------
  Defines
  ---------------------------------------------------------------------------*/

#define RECIPE_ID "xsh_scired_ifu_offset"
#define RECIPE_AUTHOR "A.Modigliani, J.Vernet, P. Bristow"
#define RECIPE_CONTACT "Andrea.Modigliani@eso.org"

/*-----------------------------------------------------------------------------
  Functions prototypes
  ----------------------------------------------------------------------------*/

/*
 *   Plugin initalization, execute and cleanup handlers
 */

static int xsh_scired_ifu_offset_create( cpl_plugin *);
static int xsh_scired_ifu_offset_exec( cpl_plugin *);
static int xsh_scired_ifu_offset_destroy( cpl_plugin *);

/* The actual executor function */
static void xsh_scired_ifu_offset( cpl_parameterlist *, cpl_frameset *);

/*-----------------------------------------------------------------------------
  Static variables
  ----------------------------------------------------------------------------*/
static char xsh_scired_ifu_offset_description_short[] =
"Reduce science IFU on-off exposures and build a 3D cube";

static char xsh_scired_ifu_offset_description[] =
"This recipe Reduce science IFU on-off exposures and build a 3D cube\n\
Input Frames : \n\
  - A set of 2xn Science frames, \
      Tag = OBJECT_IFU_OFFSET_arm, SKY_IFU_arm\n\
  - A spectral format table (Tag = SPECTRAL_FORMAT_TAB_arm)\n\
  - A master flat frame (Tag = MASTER_FLAT_IFU_arm)\n\
  - An order table frame(Tag = ORDER_TABLE_EDGES_IFU_arm)\n\
  - 3 wave solution frames, one per slitlet (Tag = WAVE_TAB_ARC_IFU_slitlet_arm)\n\
      where 'slitlet' is DOWN, CEN or UP\n\
  - [OPTIONAL] A dispersion table (Tag = DISP_TAB_IFU_arm)\n\
  - [OPTIONAL] A non-linear badpixel map (Tag = BP_MAP_NL_arm)\n\
  - [OPTIONAL] A reference badpixel map (Tag = BP_MAP_RP_arm)\n\
Products : \n\
 - Merged 3D data cube (PREFIX_MERGE3D_DATA_OBJ_arm)\n\
 - QC Traces of 3D data cube (PREFIX_MERGE3D_TRACE_OBJ_arm)\n\
 - Order by order 3D data cube (PREFIX_ORDER3D_DATA_OBJ_arm)\n\
 - Order by order 3D qual cube (IFU_CFG_COR_arm)\n\
 - Order by order 3D qual cube (PREFIX_MERGE3D_DATA_SKY_arm)\n\
 - where PREFIX is SCI, FLUX, TELL if input raw DPR.TYPE contains OBJECT or FLUX or TELLURIC\n\
 - 1 Spectrum merge 3D, PRO.CATG=MERGE3D_IFU_arm\n" ;

/*-----------------------------------------------------------------------------
  Functions code
  ----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/**
   @brief    Build the list of available plugins, for this module.
   @param    list    the plugin list
   @return   0 if everything is ok, -1 otherwise

   Create the recipe instance and make it available to the application using the
   interface. This function is exported.
*/
/*----------------------------------------------------------------------------*/

int cpl_plugin_get_info(cpl_pluginlist *list) {
  cpl_recipe *recipe = NULL;
  cpl_plugin *plugin = NULL;

  recipe = cpl_calloc(1, sizeof(*recipe));
  if ( recipe == NULL ){
    return -1;
  }

  plugin = &recipe->interface ;

  cpl_plugin_init(plugin,
                  CPL_PLUGIN_API,                    /* Plugin API */
                  XSH_BINARY_VERSION,             /* Plugin version */
                  CPL_PLUGIN_TYPE_RECIPE,            /* Plugin type */
                  RECIPE_ID,                         /* Plugin name */
                  xsh_scired_ifu_offset_description_short,   /* Short help */
                  xsh_scired_ifu_offset_description,        /* Detailed help */
                  RECIPE_AUTHOR,                     /* Author name */
                  RECIPE_CONTACT,                    /* Contact address */
                  xsh_get_license(),                 /* Copyright */
                  xsh_scired_ifu_offset_create,
                  xsh_scired_ifu_offset_exec,
                  xsh_scired_ifu_offset_destroy);

  cpl_pluginlist_append(list, plugin);

  return (cpl_error_get_code() != CPL_ERROR_NONE);
}

/*----------------------------------------------------------------------------*/
/**
   @brief    Setup the recipe options
   @param    plugin  the plugin
   @return   0 if everything is ok

   Create the recipe instance and make it available to the application using the
   interface.

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

static int xsh_scired_ifu_offset_create(cpl_plugin *plugin){
  cpl_recipe *recipe = NULL;

  xsh_clipping_param crh_clip_param = {5.0, 5, 0.7, 0,0.3};
  /* First param (conv_kernel) should be initialized correctly ! */
  xsh_remove_crh_single_param crh_single = { 0.1, 5, 2.0, 4} ;
  xsh_rectify_param rectify = { "tanh",
                                CPL_KERNEL_DEFAULT, 
                                2,
                                -1.0, 
                                -1.0,
                                1,0,0.};
  /* 2nd and 3rd params should be initialized correctly */
  xsh_localize_obj_param loc_obj = 
     {10, 0.1, 0, 0, LOC_MANUAL_METHOD, 0, 2.0,3,3,FALSE};
  xsh_stack_param stack_param = {"median",5.,5.};
/*
  xsh_extract_param extract_par = 
    { LOCALIZATION_METHOD};
*/
  /* Reset library state */
  xsh_init();

  /* Check input */
  assure( plugin != NULL, CPL_ERROR_NULL_INPUT, "Null plugin");
  /* Get the recipe out of the plugin */
  assure( cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE,
          CPL_ERROR_TYPE_MISMATCH,
          "Plugin is not a recipe");

  recipe = (cpl_recipe *)plugin;

  /* Create the parameter list in the cpl_recipe object */
  recipe->parameters = cpl_parameterlist_new();
  assure( recipe->parameters != NULL,
          CPL_ERROR_ILLEGAL_OUTPUT,
          "Memory allocation failed!");

  /* Set generic parameters (common to all recipes) */
  check( xsh_parameters_generic( RECIPE_ID, recipe->parameters ) ) ;
  xsh_parameters_decode_bp(RECIPE_ID,recipe->parameters,-1);
  check( xsh_parameters_pre_overscan( RECIPE_ID, recipe->parameters ) ) ;
  check(xsh_parameters_stack_create(RECIPE_ID,recipe->parameters,stack_param));
  /* crh clipping params */
  check(xsh_parameters_clipping_crh_create(RECIPE_ID,recipe->parameters,
    crh_clip_param));

  /* subtract_background_params AMO removed these
  check(xsh_parameters_background_create(RECIPE_ID,recipe->parameters));
  */
  /* remove_crh_single */
  check(xsh_parameters_remove_crh_single_create(RECIPE_ID,recipe->parameters,
						crh_single )) ;
  /* xsh_rectify */
  check(xsh_parameters_rectify_create(RECIPE_ID,recipe->parameters,
					    rectify )) ;
  /* xsh_localize_object */
  check(xsh_parameters_localize_obj_create(RECIPE_ID,recipe->parameters,
					   loc_obj )) ;

  /* xsh_optimal_extract
  check(xsh_parameters_optimal_extract_create(RECIPE_ID,
					      recipe->parameters,-1. )) ;
					      */
  /* trivial extract (Just temporary)
  check(xsh_parameters_extract_create(RECIPE_ID,
				      recipe->parameters,
				      extract_par,LOCALIZATION_METHOD )) ;
                                     
  */
  /* single rectify localization */
  check( xsh_parameters_new_boolean( recipe->parameters, RECIPE_ID,
    "compute-map", FALSE,
     "if TRUE recompute (wave and slit) maps from the dispersion solution. If sky-subtract is set to TRUE this must be set to TRUE."));
 
  check( xsh_parameters_new_boolean( recipe->parameters, RECIPE_ID,
    "trace-obj", FALSE,
     "if TRUE trace object position on each IFU slice. In this case order TAB edges is required"));
 

  check( xsh_parameters_new_boolean( recipe->parameters, RECIPE_ID,
    "check-afc", TRUE,
     "Input AFC corrected model/wave solution and science frame check. If TRUE the recipe verify that the input mode/wave solution is AFC corrected, its INS.OPTIi.NAME is 'Pin_0.5 ', and its OBS.ID and OBS.TARG.NAME values matches with the corresponding values of the science frame."));

  check( xsh_parameters_new_boolean( recipe->parameters, RECIPE_ID,
      "cut-uvb-spectrum", TRUE,
      "TRUE if recipe cuts the UVB spectrum at 556 nm (dichroich)"));

  cleanup:
    if ( cpl_error_get_code() != CPL_ERROR_NONE ){
      xsh_error_dump(CPL_MSG_ERROR);
      return 1;
    }
    else {
      return 0;
    }
}

/*----------------------------------------------------------------------------*/
/**
   @brief    Execute the plugin instance given by the interface
   @param    plugin  the plugin
   @return   0 if everything is ok
*/
/*----------------------------------------------------------------------------*/

static int xsh_scired_ifu_offset_exec(cpl_plugin *plugin) {
  cpl_recipe *recipe = NULL;

  /* Check parameter */

  assure( plugin != NULL, CPL_ERROR_NULL_INPUT, "Null plugin");

  /* Get the recipe out of the plugin */
  assure( cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE,
          CPL_ERROR_TYPE_MISMATCH, "Plugin is not a recipe");

  recipe = (cpl_recipe *)plugin;

  /* Check recipe */
  xsh_scired_ifu_offset(recipe->parameters, recipe->frames);

  cleanup:
    if ( cpl_error_get_code() != CPL_ERROR_NONE ) {
      xsh_error_dump(CPL_MSG_ERROR);
      xsh_error_reset();
      return 1;
    }
    else {
      return 0;
    }
}

/**
@brief monitor parameters value
@param backg inter-order background parameters
@param rectify_par rectification parameters
@return cpl_error_code
 */
static cpl_error_code 
xsh_params_monitor(xsh_rectify_param * rectify_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);

  return cpl_error_get_code();

}
#if 0
/*--------------------------------------------------------------------------*/
/**
  @brief    Scale input parameters for binning
  @param    raws   the frames list
  @param    backg inter-order background correction

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

static cpl_error_code 
xsh_params_bin_scale(cpl_frameset* raws,
                     xsh_background_param* backg)
{

  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;
    Not bin dependent.
    */

    backg->radius_y=backg->radius_y/biny;
    /*
    if(backg->smooth_y>0) {
      backg->smooth_y=backg->smooth_y/biny;
    }
    Smoothing radius' half size in y 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
    */

  }


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

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

}
#endif

/*----------------------------------------------------------------------------*/
/**
   @brief    Destroy what has been created by the 'create' function
   @param    plugin  the plugin
   @return   0 if everything is ok
*/
/*----------------------------------------------------------------------------*/
static int xsh_scired_ifu_offset_destroy(cpl_plugin *plugin)
{
  cpl_recipe *recipe = NULL;

  /* reset error state before detroying recipe */
  xsh_error_reset(); 
  /* Check parameter */
  assure( plugin != NULL, CPL_ERROR_NULL_INPUT, "Null plugin" );

  /* Get the recipe out of the plugin */
  assure( cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE,
    CPL_ERROR_TYPE_MISMATCH, "Plugin is not a recipe");

  recipe = (cpl_recipe *)plugin;

  xsh_free_parameterlist(&recipe->parameters);

 cleanup:
  if (cpl_error_get_code() != CPL_ERROR_NONE)
    {
      return 1;
    }
  else
    {
      return 0;
    }
}


/*----------------------------------------------------------------------------*/
/**
   @brief    Interpret the command line options and execute the data processing
   @param    parameters     the parameters list
   @param    frameset   the frames list

   In case of failure the cpl_error_code is set.
*/
/*----------------------------------------------------------------------------*/
static void xsh_scired_ifu_offset( cpl_parameterlist* parameters, 
				   cpl_frameset* frameset)
{
  const char* recipe_tags[4] = {XSH_OBJECT_IFU_OFFSET, XSH_STD_TELL_IFU_OFFSET, XSH_STD_FLUX_IFU_OFFSET, XSH_SKY_IFU};
  int recipe_tags_size = 4;

  /* Beware, do not "free" the following input frames, they are part
     of the input frameset */
  cpl_frame *spectral_format_frame = NULL;
  cpl_frame *ifu_cfg_tab_frame = NULL ;
  cpl_frame *ifu_cfg_cor_frame = NULL ;
  //int nobj=0;
  //int nsky=0;

  /* Input frames */
  cpl_frameset* raws = NULL;
  cpl_frameset* calib = NULL;
  /* Beware, do not "free" the following input frames, they are part
     of the input frameset */
  cpl_frame* bpmap = NULL;
  cpl_frame * master_bias = NULL ;
  cpl_frame * master_dark = NULL ;
  cpl_frame* master_flat = NULL;
  cpl_frame* order_tab_edges = NULL;
  cpl_frame * wavesol_frame = NULL ;
  cpl_frame * model_config_frame = NULL ;
  //cpl_frame * spectral_format = NULL ;
  cpl_frame * slice_offset_frame = NULL ;
  cpl_frameset * raw_object = NULL, * raw_sky = NULL ;
  xsh_stack_param* stack_par=NULL;
  /* Parameters */
  //xsh_background_param* backg_par = NULL;
  xsh_remove_crh_single_param * crh_single_par = NULL ;
  xsh_rectify_param * rectify_par = NULL ;


  xsh_instrument* instrument = NULL;
  int nb_sub_frames ;
  int nb_raw_frames ;

  /* Intermediate frames */

  cpl_frameset * sub_frameset = NULL ;	/**< frameset of subtracted offset frames */
  //cpl_frameset * rmbkg_frameset = NULL ; /**< frameset of frames after subtract bkg */
  cpl_frameset * clean_frameset = NULL ; /**< frameset of clean frames after
					  divide flat */
  cpl_frame * comb_obj_frame = NULL ; /**< Comined frame */
  cpl_frameset * rect2_frameset = NULL ; /**< Rectifid frame set */
  //cpl_frameset * loc_table_frameset = NULL ; /**< Output of xsh_localize_object */

  /* Output Frames (results)*/
  cpl_frameset * res_1D_frameset = NULL ;	/**< Final (result) frame */
  cpl_frameset * res_2D_frameset = NULL ;
  cpl_frame * data_cube = NULL ;
  cpl_frameset * ext_frameset = NULL ;
  cpl_frameset * ext_frameset_tables = NULL ;
  char* prefix=NULL;
 
  char  arm_str[16] ;
  char  * file_tag = NULL;
  cpl_frame* grid_backg=NULL;
  cpl_frame* frame_backg=NULL;
  cpl_frameset * ext_frameset_images = NULL ; /**< frameset of rectified frames */
  cpl_frameset * rect2_frameset_tables = NULL ; /**< frameset of rectified frames */
  //cpl_frameset * rect_frameset_tab=NULL;
  //cpl_frameset * rect_frameset_eso=NULL;
  char rec_prefix[256];
  char sky_prefix[256];
  //cpl_frame* object_frame=NULL;
  //int check_afc = TRUE;
  int do_compute_map = TRUE;
  int recipe_use_model = FALSE;
  //char wave_map_tag[256];
  //char slit_map_tag[256];
  cpl_frame *wavemap = NULL ;
  cpl_frame *slitmap = NULL ;
  cpl_frame *disp_tab_frame = NULL;
  cpl_frame* comb_sky_frame=NULL;
  int pre_overscan_corr=0;
  cpl_frame* ifu_sky_map=NULL;
  int do_computemap=1;
  int use_model=0;
  cpl_frameset* crh_clean_obj = NULL;
  cpl_frameset* crh_clean_sky = NULL;
  cpl_frame* sky_map_frm = NULL;
  int do_flatfield = 1;
  /**************************************************************************/
  /* DFS management */
  /**************************************************************************/
  check( xsh_begin( frameset, parameters, &instrument, &raws, &calib,
                    recipe_tags, recipe_tags_size,
                    RECIPE_ID, XSH_BINARY_VERSION,
                    xsh_scired_ifu_offset_description_short));

  check(xsh_ensure_raws_input_offset_recipe_is_proper(&raws,instrument));
  assure( instrument->mode == XSH_MODE_IFU, CPL_ERROR_ILLEGAL_INPUT,
	  "Instrument NOT in Ifu Mode" ) ;
  check(xsh_recipe_params_check(parameters,instrument,RECIPE_ID));
  /* One should have a multiple of 2 input frames: A-B */
  check( nb_raw_frames = cpl_frameset_get_size( raws ) ) ;
  xsh_msg( "Nb of Raw frames: %d", nb_raw_frames ) ;

  XSH_ASSURE_NOT_ILLEGAL( nb_raw_frames > 1  ) ;
  {

    int even_nb = nb_raw_frames % 2 ;
    XSH_ASSURE_NOT_ILLEGAL( even_nb == 0 ) ;

  }
 

  /**************************************************************************/
  /* Recipe frames */
  /**************************************************************************/


  /* IFU stuff (physmodel) */
  check(ifu_cfg_tab_frame=xsh_find_frame_with_tag(calib,XSH_IFU_CFG_TAB,instrument));
  check(ifu_cfg_cor_frame=xsh_find_frame_with_tag(calib,XSH_IFU_CFG_COR,instrument));
  check(spectral_format_frame=xsh_find_spectral_format( calib, instrument ) ) ;


  check(bpmap=xsh_check_load_master_bpmap(calib,instrument,RECIPE_ID));
  /* 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_frame_with_tag(calib,XSH_MASTER_BIAS,
						 instrument));
  }
  /* IN NIR mode */
  else {
    /* split on and off files */
    /*check(xsh_dfs_split_nir(raws,&on,&off));
    XSH_ASSURE_NOT_ILLEGAL(cpl_frameset_get_size(on) >= 3);
    XSH_ASSURE_NOT_ILLEGAL(cpl_frameset_get_size(off) >= 3);*/
  }
  check(order_tab_edges = xsh_find_order_tab_edges(calib,instrument));

  /* one should have either model config frame or wave sol frame */
   check(model_config_frame=xsh_find_frame_with_tag(calib,XSH_MOD_CFG_OPT_AFC,
                                                    instrument));

   if(model_config_frame==NULL) {
      check(wavesol_frame=xsh_find_frame_with_tag(calib,XSH_WAVE_TAB_AFC,
                                                  instrument));
   }

   /*
   check( check_afc = xsh_parameters_get_boolean( parameters, RECIPE_ID,
                                                  "check-afc"));
   */
    check( do_compute_map = xsh_parameters_get_boolean( parameters, RECIPE_ID,
                                                        "compute-map"));

  /*
    One of model config and wave tab must be present, but only one !
  */
  XSH_ASSURE_NOT_ILLEGAL( (model_config_frame != NULL && wavesol_frame == NULL ) ||  

			  (model_config_frame == NULL && wavesol_frame != NULL ) );

  check( master_flat = xsh_find_master_flat( calib, instrument ) ) ;

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


  if ((slice_offset_frame = xsh_find_frame_with_tag( calib, XSH_SLICE_OFFSET,
						     instrument) ) == NULL ) {
    xsh_msg_warning("Frame %s not provided", XSH_SLICE_OFFSET );
    xsh_error_reset() ;
  }


  /**************************************************************************/
  /* Recipe parameters */
  /**************************************************************************/
  check( stack_par = xsh_stack_frames_get( RECIPE_ID, parameters));

  /*
  check( backg_par = xsh_parameters_background_get(RECIPE_ID,
    parameters));
  */
  check( rectify_par = xsh_parameters_rectify_get(RECIPE_ID,
     parameters));
  rectify_par->conserve_flux=FALSE;
  check( crh_single_par = xsh_parameters_remove_crh_single_get(RECIPE_ID,
    parameters));
  if ( rectify_par->rectify_full_slit == 1 ) {
    xsh_msg( "Use Full Slit" ) ;
  }
  else {
    xsh_msg( "Use Max Possible Slit" ) ;
  }
  check(xsh_rectify_params_set_defaults(parameters,RECIPE_ID,instrument,rectify_par));

  /* adjust relevant parameter to binning 
  if ( xsh_instrument_get_arm( instrument ) != XSH_ARM_NIR ) {
    check(xsh_params_bin_scale(raws,backg_par));
  }
  */
  check(xsh_params_monitor(rectify_par));


  /**************************************************************************/
  /* Recipe code */
  /**************************************************************************/

  /* prepare RAW frames in PRE format */
  check(xsh_prepare(raws, bpmap, master_bias, XSH_OBJECT_IFU_OFFSET,
		    instrument,pre_overscan_corr,CPL_TRUE));

  /* make sure each input raw frame has the same exp time */
  check(xsh_frameset_check_uniform_exptime(raws,instrument));

  /* Separate OBJECT and SKY frames */
  check( nb_sub_frames = xsh_dfs_split_offset( raws, "IFU_OFFSET",
				   XSH_SKY_IFU, &raw_object,
					   &raw_sky ) ) ;

  //nobj=cpl_frameset_get_size(raw_object);
  //nsky=cpl_frameset_get_size(raw_sky);
  prefix=xsh_set_recipe_file_prefix(raws,"xsh_scired_ifu_offset");
  sprintf(sky_prefix,xsh_set_recipe_sky_file_prefix(rec_prefix));
  check(strcpy(rec_prefix,(const char*)prefix));
  XSH_FREE(prefix);

  //check(object_frame=cpl_frameset_get_frame(raw_object,0));
   if ( model_config_frame == NULL){
     xsh_msg("RECIPE USE WAVE SOLUTION");
     recipe_use_model = FALSE;
     do_compute_map = TRUE;
   }
   else{
     xsh_msg("RECIPE USE MODEL");
     recipe_use_model = TRUE;
   }

  if ( do_compute_map && recipe_use_model==FALSE){
     check( disp_tab_frame = xsh_find_disp_tab( calib, instrument));
   }



  xsh_msg("cmap=%d wavemap=%p slitmap=%p",do_computemap,wavemap,slitmap);
  if( (do_computemap == 1) &&
      (wavemap ==NULL || slitmap ==NULL )
      ) {
        if (model_config_frame != NULL) {
          use_model=1;
        }

        check( xsh_check_get_map( disp_tab_frame, order_tab_edges,
                master_flat, model_config_frame, calib, instrument,
                do_computemap, use_model, rec_prefix,
                &wavemap, &slitmap));

  }

  if( nb_sub_frames==0 ) {
        xsh_msg_error("nb_sub_frames=%d something wrong check your input raws",nb_sub_frames);
        goto cleanup;

  }

  /* remove crh on each obj or sky frame */
  sky_map_frm = xsh_find_frame_with_tag(calib,XSH_SKY_MAP, instrument);
  crh_clean_obj = xsh_frameset_crh_single(raw_object, crh_single_par,sky_map_frm,
                  instrument,rec_prefix,"OBJ");
  crh_clean_sky = xsh_frameset_crh_single(raw_sky, crh_single_par, sky_map_frm,
                  instrument,rec_prefix,"SKY");


  /* For each pair, subtract OBJECT-SKY */
  check( sub_frameset = xsh_subtract_sky_offset( crh_clean_obj, crh_clean_sky,
						 nb_sub_frames, instrument)) ;

  xsh_free_frameset(&crh_clean_obj);
  xsh_free_frameset(&crh_clean_sky);

  /**************************************************************************/
  /* Check that SCI IFU frame and AFC corrected CFG are proper              */
  /**************************************************************************/
/*
  if(check_afc) {
     if(model_config_frame!=NULL) {
        check(xsh_frame_check_model_cfg_is_afc_corrected(model_config_frame));
        check(xsh_frame_check_model_cfg_is_proper_for_sci(model_config_frame,
                                                          object_frame,
                                                          instrument));
     } else {
        check(xsh_frame_check_model_cfg_is_afc_corrected(wavesol_frame));
        check(xsh_frame_check_model_cfg_is_proper_for_sci(wavesol_frame,
                                                          object_frame,
                                                          instrument));
     }
  }
*/

  if (do_flatfield == 1) {
    clean_frameset=xsh_frameset_mflat_divide(sub_frameset,master_flat,instrument);
  } else {
    clean_frameset = cpl_frameset_duplicate(sub_frameset);
  }
  /* now we have duplicate sub_frameset we do not need it anymore */
  xsh_free_frameset(&sub_frameset);


  //check( rmbkg_frameset = cpl_frameset_new() ) ;
  //check( clean_frameset = cpl_frameset_new() ) ;

  sprintf( arm_str, "%s_",  xsh_instrument_arm_tostring(instrument) ) ; 

  /* AMO removed background subtraction 
  // For each sky subtracted frame 
  for( i = 0 ; i<nb_sub_frames ; i++ ) {
    cpl_frame * a_b = NULL ;
    cpl_frame * rm_bkg = NULL ;
    char str[16] ;

    sprintf( str, "%d", i ) ;
    a_b = cpl_frameset_get_frame( sub_frameset, i ) ;
    // subtract background 

    xsh_msg("Subtract inter-order background %d", i );
    sprintf(file_name,"%s%s",rec_prefix, str) ;
 
    check(rm_bkg = xsh_subtract_background( a_b,
					    order_tab_edges,
					    backg_par, instrument,
					    file_name,&grid_backg,
					    &frame_backg,0,0,0));
    check( cpl_frameset_insert( rmbkg_frameset, rm_bkg ) ) ;
  }
  */

  /* AMO removed this part doing CRH flagging and flat fielding
     as these have been already performed
  if ( nb_sub_frames < 3 && crh_single_par->nb_iter > 0 ) {
    xsh_msg( "Less than 3 frames AND crh_single_niter > 0" ) ;
    for ( i = 0 ; i < nb_sub_frames ; i++ ) {
      cpl_frame * divided = NULL ;
      cpl_frame * rm_crh = NULL ;
      cpl_frame * a_b = NULL ;
      char str[16] ;

      check( a_b = cpl_frameset_get_frame( rmbkg_frameset, i ) ) ;
      sprintf( str, "%d", i ) ;

      file_tag = xsh_stringcat_any( "NO_CRH_IFU_OFFSET_", arm_str,str,
                                    (void*)NULL ) ;
      xsh_msg( "Remove crh (single frame)" ) ;

      check( rm_crh = xsh_remove_crh_single( a_b,instrument,
					     crh_single_par,
					     file_tag ) ) ;


      XSH_FREE( file_tag ) ;
      xsh_add_temporary_file(cpl_frame_get_filename(rm_crh));
      xsh_msg( "Divide by flat" ) ;
      file_tag = xsh_stringcat_any( "FF_IFU_OFFSET_", arm_str,
				     str, (void*)NULL ) ;
      check( divided = xsh_divide_flat( rm_crh,
					master_flat, file_tag,
					instrument ) ) ;
      XSH_FREE( file_tag ) ;
      check( cpl_frameset_insert( clean_frameset, divided ) ) ;
      xsh_add_temporary_file(cpl_frame_get_filename(divided));
      xsh_free_frame(&rm_crh);

    }
  }
  else for( i = 0 ; i < nb_sub_frames ; i++ ) {
    cpl_frame * divided = NULL ;
    cpl_frame * a_b = NULL ;
    char str[16] ;

    // If enough frames, the CRH removal is done in xsh_combine_offset 
    a_b = cpl_frameset_get_frame( rmbkg_frameset, i ) ;
    sprintf( str, "%d", i ) ;

    /// Divide by flat
    xsh_msg( "Divide by flat" ) ;
    file_tag = xsh_stringcat_any( "FF_IFU_OFFSET_", arm_str,
				   str, (void*)NULL ) ;
    check( divided = xsh_divide_flat( a_b,
				      master_flat, file_tag,
				      instrument ) ) ;
    XSH_FREE( file_tag ) ;
    check( cpl_frameset_insert( clean_frameset, divided ) ) ;
    xsh_add_temporary_file(cpl_frame_get_filename(divided));
  }
  */

  /* Now combine all frames */
  xsh_msg( "Combining all frames" ) ;
  file_tag = xsh_stringcat_any( "COMBINED_IFU_OFFSET_", arm_str,
				 "ALL", (void*)NULL ) ;

  check( comb_obj_frame = xsh_combine_offset( clean_frameset,
					  file_tag, stack_par,
					  instrument, NULL, NULL,1 ) ) ;
  XSH_FREE( file_tag ) ;

  check(comb_sky_frame=xsh_util_frameset_collapse_mean(raw_sky,instrument));


  /* Now build the cube frame */

  check(xsh_build_ifu_cube(comb_obj_frame,ifu_cfg_tab_frame,ifu_cfg_cor_frame,
                           spectral_format_frame,
                           model_config_frame,wavesol_frame,
                           instrument,
                           frameset,
                           parameters,rectify_par,RECIPE_ID,rec_prefix,1));

  /* Now build the cube sky frame: we need to pass a tag to 
     identify OBJ and SKY */

  check(xsh_build_ifu_cube(comb_sky_frame,ifu_cfg_tab_frame,ifu_cfg_cor_frame,
                           spectral_format_frame,
                           model_config_frame,wavesol_frame,
                           instrument,
                           frameset,
                           parameters,rectify_par,RECIPE_ID,rec_prefix,0));

  if(do_compute_map) {
  check(ifu_sky_map=xsh_build_ifu_map(comb_obj_frame,wavemap,slitmap,instrument));
  check( xsh_add_product_image( ifu_sky_map, frameset,parameters, RECIPE_ID, instrument,NULL));
  }
  cleanup:
 
    xsh_end( RECIPE_ID, frameset, parameters );
    //XSH_FREE( backg_par ) ;
    XSH_FREE( crh_single_par ) ;
    XSH_FREE( rectify_par ) ;
    XSH_FREE(stack_par);
    xsh_instrument_free(&instrument );
    xsh_free_frame(&wavemap);
    xsh_free_frame(&slitmap);
    xsh_free_frameset(&ext_frameset_images);
    xsh_free_frameset(&rect2_frameset_tables);
    xsh_free_frameset(&ext_frameset_tables);

    xsh_free_frameset(&raw_object);
    xsh_free_frameset(&raw_sky);
    xsh_free_frameset(&raws);
    xsh_free_frameset(&calib);
    xsh_free_frameset( &sub_frameset ) ;
    xsh_free_frameset( &clean_frameset ) ;
    //xsh_free_frameset( &rmbkg_frameset ) ;
    xsh_free_frameset(&res_1D_frameset) ;
    xsh_free_frameset(&res_2D_frameset) ;
    xsh_free_frameset(&rect2_frameset) ;
    xsh_free_frameset(&ext_frameset) ;

 
    xsh_free_frame( &comb_sky_frame);
    xsh_free_frame( &comb_obj_frame);
    xsh_free_frame( &grid_backg);
    xsh_free_frame( &frame_backg);

    xsh_free_frame( &data_cube ) ;
 
    return;
}

/**@}*/
