/*                                                                            *
 *   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-02-04 12:44:59 $
 * $Revision: 1.113 $
 *
*/

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

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

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


/* DRL steps */

/* Error handling */
#include <xsh_error.h>
/* Utility fonctions */
#include <xsh_utils_image.h>
#include <xsh_utils_ifu.h>
#include <xsh_msg.h>
/* DFS functions */
#include <xsh_dfs.h>
#include <xsh_pfits.h>
/* DRL functions */
#include <xsh_drl_check.h>
#include <xsh_drl.h>
#include <xsh_data_spectrum1D.h>
#include <xsh_model_arm_constants.h>
#include <xsh_blaze.h>
/* Library */
#include <cpl.h>
/* CRH Remove */

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

#define RECIPE_ID "xsh_scired_ifu_stare_drl"
#define RECIPE_AUTHOR "P.Goldoni, L.Guglielmi, R. Haigron, F. Royer"
#define RECIPE_CONTACT "amodigli@eso.org"

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

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

static int xsh_scired_ifu_stare_create(cpl_plugin *);
static int xsh_scired_ifu_stare_exec(cpl_plugin *);
static int xsh_scired_ifu_stare_destroy(cpl_plugin *);

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

/*-----------------------------------------------------------------------------
  Static variables
  ----------------------------------------------------------------------------*/
static char xsh_scired_ifu_stare_description_short[] =
"Reduce science exposure in IFU configuration and stare mode";

static char xsh_scired_ifu_stare_description[] =
"This recipe reduces science exposure in IFU configuration and stare mode\n\
Input Frames : \n\
  - A set of n Science frames ( n == 1 or >=3, \
Tag = OBJECT_IFU_STARE_arm or STD_TELL_IFU_STARE_arm or STD_FLUX_IFU_STARE_arm)\n\
  - A spectral format table (Tag = SPECTRAL_FORMAT_TAB_arm)\n\
  - [UVB,VIS] A master bias frame (Tag = MASTER_BIAS_arm)\n\
  - [OPTIONAL]A master dark frame (Tag = MASTER_DARK_arm)\n\
  - A master flat frame (Tag = MASTER_FLAT_IFU_arm)\n\
  - An AFC corrected order table frame (Tag = ORDER_TAB_AFC_IFU_arm)\n\
  - [physmod] An AFC corrected model cfg frame (Tag = XSH_MOD_CFG_OPT_AFC_arm)\n\
  - [poly] An AFC corrected model wavesol frame (Tag = WAVE_TAB_AFC_arm) \n\
  - [OPTIONAL] An AFC corrected dispersion solution frame (Tag = DISP_TAB_AFC_arm)\n\
  - [OPTIONAL] A slit map (Tag = SLIT_MAP_arm)\n\
  - [OPTIONAL] A badpixel map (Tag = BADPIXEL_MAP_arm)\n\
  - [OPTIONAL] A mask of telluric lines (Tag = TELL_MASK_arm)\n\
Products : \n\
  - 3 Spectrum order tables 2D (1 per slitlet), PRO.CATG=ORDER2D_slitlet_IFU_arm\n\
  - 3 Spectrum merge tables 2D (1 per slitlet), PRO.CATG=MERGE2D_slitlet_IFU_arm\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_stare_description_short, /* Short help */
                  xsh_scired_ifu_stare_description,       /* Detailed help */
                  RECIPE_AUTHOR,                     /* Author name */
                  RECIPE_CONTACT,                    /* Contact address */
                  xsh_get_license(),                 /* Copyright */
                  xsh_scired_ifu_stare_create,
                  xsh_scired_ifu_stare_exec,
                  xsh_scired_ifu_stare_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_stare_create(cpl_plugin *plugin){
  cpl_recipe *recipe = NULL;
  cpl_parameter* p=NULL;
  char paramname[256];
  char recipename[256];
  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,
				XSH_WAVE_BIN_SIZE_PIPE_NIR,
				XSH_SLIT_BIN_SIZE_PIPE_NIR,
                                1,
				0, 0.};

  xsh_stack_param stack_param = {"median",5.,5.};
  /* 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_extract_param extract_par = 
    { LOCALIZATION_METHOD};
  xsh_interpolate_bp_param ipol_par = {30 };
  /* 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 */
  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 )) ;


  /* trivial extract (Just temporary) */
  check(xsh_parameters_extract_create(RECIPE_ID,
				      recipe->parameters,
				      extract_par,LOCALIZATION_METHOD )) ;

  check(xsh_parameters_interpolate_bp_create(RECIPE_ID,
					   recipe->parameters,ipol_par)) ;
    check( xsh_parameters_new_double( recipe->parameters, RECIPE_ID,
    "shift-offsettab-low", 0.0,
     "Global shift of the lower slitlet slit positions, relative to the central one[arcsec]."));
check( xsh_parameters_new_double( recipe->parameters, RECIPE_ID,
    "shift-offsettab-up", 0.0,
     "Global shift of the upper slitlet slit positions, relative to the central one[arcsec]."));

  check( xsh_parameters_new_boolean( recipe->parameters, RECIPE_ID,
    "compute-map", TRUE,
     "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,
    "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."));
     
   sprintf(recipename,"xsh.%s",RECIPE_ID);
  sprintf(paramname,"%s.%s",recipename,"flat-method");
  check( p = cpl_parameter_new_enum( paramname,CPL_TYPE_STRING,
				   "method adopted for flat:",
				   recipename,"master",
                                   2,"master","blaze"));

  check(cpl_parameter_set_alias( p,CPL_PARAMETER_MODE_CLI,
    "flat-method"));
  check(cpl_parameterlist_append( recipe->parameters, p));

 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_stare_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_stare(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    Destroy what has been created by the 'create' function
   @param    plugin  the plugin
   @return   0 if everything is ok
*/
/*----------------------------------------------------------------------------*/
static int xsh_scired_ifu_stare_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;
    }
}


static cpl_error_code 
xsh_params_monitor(xsh_background_param* backg,
                   xsh_rectify_param * rectify_par,
                   xsh_localize_obj_param * loc_obj_par)
{


  xsh_msg_dbg_low("bkg params: sampley=%d radius_y=%d",
	  backg->sampley,backg->radius_y);

  xsh_msg_dbg_low("bkg params: radius_x=%d",
	  backg->radius_x);

  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();

}
/*--------------------------------------------------------------------------*/
/**
  @brief    Scales input parameters for binning
  @param    raws   the frames list
  @param    backg  the structure controlling inter-order bacground computation

  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;
    number of points of the grid in y direction.
    Not to be bin dependent
    */

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

    /* bin dependent */


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

  }


  if(binx>1) {

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

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

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

}

/*----------------------------------------------------------------------------*/
/**
   @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_stare(cpl_parameterlist* parameters,
				  cpl_frameset* frameset)
{
  const char* recipe_tags[3] = {XSH_OBJECT_IFU_STARE,
                                XSH_STD_TELL_IFU_STARE,
                                XSH_STD_FLUX_IFU_STARE};
  int recipe_tags_size = 3;

  /* Input frames */
  xsh_instrument *instrument = NULL;
  int nb_raw_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 *wavetab_frame = NULL;
  cpl_frameset *wavetab_frameset = NULL ;
  cpl_frame *model_config_frame = NULL ;
  cpl_frame *spectral_format = NULL ;
  cpl_frame *disp_tab_frame = NULL;
  cpl_frame *shifttab_frame = NULL;

  /* Parameters */
  xsh_clipping_param *crh_clipping_par = NULL;
  xsh_background_param *backg_par = NULL;
  xsh_remove_crh_single_param *crh_single_par = NULL ;
  xsh_rectify_param *rectify_par = NULL ;
  xsh_localize_obj_param *loc_obj_par = NULL ;
  int merge_par = 0;
  xsh_extract_param *extract_par = NULL ;
  double offset_low =0.0;
  double offset_up =0.0;

  xsh_stack_param* stack_par=NULL;

  int recipe_use_model = FALSE;
  int do_computemap = 0;
  int check_afc = TRUE;

  /* Intermediate frames */
  cpl_frame *slitmap_frame = NULL;
  cpl_frame *wavemap_frame = NULL;
  cpl_frame *crhm_frame = NULL ;	/**< Output of remove_crh */
  cpl_frame *rmbias = NULL;	/**< Output of subtract bias */
  cpl_frame *rmdark = NULL;	/**< Output of subtract dark */
  cpl_frame *rmbkg = NULL ;	/**< Output of subtract background */
  cpl_frame *clean_frame = NULL ; /**< Output of remove_crh_single */
  cpl_frame *div_frame = NULL ; /**< Output of xsh_divide_flat */
  cpl_frameset *rect_frameset = NULL ; /**< Output of xsh_rectify_ifu */
  cpl_frameset *loc_table_frameset = NULL ; /**< Output of xsh_localize_object */

  /* Output Frames (results)*/
  cpl_frameset *res_2D_frameset = NULL ;	/**< Final (result) frame */
  cpl_frame *data_cube = NULL ;
  char div_tag[256];
  char prefix[256];
  const char * ftag=NULL;
  cpl_frame* grid_backg=NULL;
  cpl_frame* frame_backg=NULL;
  cpl_frameset* rect_frameset_eso=NULL;
  cpl_frameset* rect_frameset_tab=NULL;
  char *rec_prefix = NULL;
  int pre_overscan_corr=0;
  
  cpl_frameset *shiftifu_frameset = NULL;
  cpl_frameset *nshiftifu_frameset = NULL;
  int i;

  cpl_propertylist* plist=NULL;
  const char* name=NULL;
  const char* tag="";
  int naxis2=0;
  cpl_frame* qc_trace_frame=NULL;
  int save_size=0;
  const int peack_search_hsize=5;
  int method=0;
  char* flat_method = NULL;

  //cpl_frame *tellmask_frame = NULL;
  cpl_frame * blaze_frame = NULL;
  
  /**************************************************************************/
  /* DFS management */
  /**************************************************************************/
  check( xsh_begin( frameset, parameters, &instrument, &raws, &calib,
                    recipe_tags, recipe_tags_size,
                    RECIPE_ID, XSH_BINARY_VERSION,
                    xsh_scired_ifu_stare_description_short ) ) ;

  assure( instrument->mode == XSH_MODE_IFU, CPL_ERROR_ILLEGAL_INPUT,
	  "Instrument NOT in IFU Mode" ) ;

  xsh_recipe_params_check(parameters,instrument,RECIPE_ID);
  /* One should have 1 or >=3 input frames. 2 is not permitted */
  check( nb_raw_frames = cpl_frameset_get_size( raws));

  XSH_ASSURE_NOT_ILLEGAL_MSG( nb_raw_frames == 1 || nb_raw_frames >= 3, 
    "This recipe expects either one or at least 3 input raw frames" );

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

  bpmap = xsh_find_master_bpmap(calib);

  /* 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));
  }

  if(NULL==(order_tab_edges=xsh_find_frame_with_tag(calib,XSH_ORDER_TAB_AFC_IFU,
						    instrument))) {
    xsh_msg_error("Missing frame %s_%s", XSH_ORDER_TAB_AFC_IFU,
		  xsh_instrument_arm_tostring( instrument ));
    goto cleanup;
  }

  /* 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) {
    wavetab_frame = xsh_find_wave_tab( calib, instrument);
  }
  /*
    One of model config and wave tab must be present, but only one !
  */
  if ( model_config_frame == NULL){
    xsh_msg("RECIPE USE WAVE SOLUTION");
    recipe_use_model = FALSE;
  }
  else{
    xsh_msg("RECIPE USE MODEL");
    recipe_use_model = TRUE;
  }
  XSH_ASSURE_NOT_ILLEGAL( (model_config_frame != NULL && wavetab_frame == NULL ) ||
			  (model_config_frame == NULL && wavetab_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();
  }
  check(spectral_format=xsh_find_spectral_format( calib, instrument ) ) ;
  check( xsh_instrument_update_from_spectralformat( instrument,
						    spectral_format));

  /* OPTIONAL */
  shiftifu_frameset = xsh_find_offset_tab_ifu( calib, 
    instrument);
  xsh_error_reset();
  /*
  tellmask_frame =  xsh_find_frame_with_tag( calib, XSH_TELL_MASK, 
    instrument);
  xsh_error_reset() ;
  */
  shifttab_frame = xsh_find_frame_with_tag( calib, XSH_SHIFT_TAB_IFU, 
    instrument);
  xsh_error_reset() ;

  if ( recipe_use_model == FALSE){
    check( wavetab_frameset = xsh_ifu_wavetab_create( wavetab_frame,
      shifttab_frame, instrument));
  }
  
  /**************************************************************************/
  /* Recipe parameters */
  /**************************************************************************/
  check( stack_par = xsh_stack_frames_get( RECIPE_ID, parameters));
  check( crh_clipping_par = xsh_parameters_clipping_crh_get(RECIPE_ID,
    parameters));
  check( backg_par = xsh_parameters_background_get(RECIPE_ID,
    parameters));

  check( loc_obj_par = xsh_parameters_localize_obj_get(RECIPE_ID,
     parameters));
  check( rectify_par = xsh_parameters_rectify_get(RECIPE_ID,
     parameters));
  rectify_par->conserve_flux=FALSE;
  backg_par->method=TRUE;
  check( crh_single_par = xsh_parameters_remove_crh_single_get(RECIPE_ID,
    parameters));

  check( extract_par = xsh_parameters_extract_get( RECIPE_ID, parameters));

  check( do_computemap = xsh_parameters_get_boolean( parameters, RECIPE_ID,
    "compute-map"));

  check( check_afc = xsh_parameters_get_boolean( parameters, RECIPE_ID,
    "check-afc"));
    
  if ( do_computemap && recipe_use_model==FALSE){
    check( disp_tab_frame = xsh_find_disp_tab( calib, instrument));
  }

  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(backg_par,rectify_par,loc_obj_par));

  check( offset_low = xsh_parameters_get_double( parameters, RECIPE_ID,
    "shift-offsettab-low"));

  check( offset_up = xsh_parameters_get_double( parameters, RECIPE_ID,
    "shift-offsettab-up"));

  /* update slitlets with manual shift */
  if ( shiftifu_frameset != NULL){
    xsh_msg("offset low %f up %f", offset_low, offset_up);
    check( nshiftifu_frameset = xsh_shift_offsettab( shiftifu_frameset,
      offset_low, offset_up));
  }
  /**************************************************************************/
  /* Recipe code */
  /**************************************************************************/

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

  check( rec_prefix = xsh_set_recipe_file_prefix( raws,
    RECIPE_ID));

  /* Removing Cosmic Rays (if more than 2 frames */
  ftag = XSH_GET_TAG_FROM_ARM( XSH_IFU_STARE_REMOVE_CRH, instrument);
  check( crhm_frame = xsh_check_remove_crh_multiple( raws, ftag,
   stack_par,NULL, instrument, NULL, NULL));

  /* Get wavemap and slitmap */
  check( xsh_check_get_map( disp_tab_frame, order_tab_edges,
    crhm_frame, model_config_frame, calib, instrument,
    do_computemap, recipe_use_model, rec_prefix,
    &wavemap_frame, &slitmap_frame));

  /* Subtract bias if necessary */
  sprintf(prefix,"%s_",rec_prefix);
  /* AMO: here one schould check is pre-overscan was corrected */
  check( rmbias = xsh_check_subtract_bias( crhm_frame, master_bias,
					    instrument, rec_prefix,
                                           pre_overscan_corr,0));
					    
  /**************************************************************************/
  /* Check that SCI IFU frame and AFC corrected CFG are proper              */
  /**************************************************************************/
  check( xsh_check_afc( check_afc, model_config_frame, 
    rmbias, wavetab_frameset, order_tab_edges, disp_tab_frame, 
    instrument));
    
  /* Subtract dark if necessary */
  check( rmdark = xsh_check_subtract_dark( rmbias, master_dark,
    instrument, rec_prefix));

  /* Subtract background */
  xsh_msg("Subtract inter-order background");
  check(rmbkg = xsh_subtract_background( rmdark,
					 order_tab_edges,
					 backg_par, instrument, 
					 rec_prefix,&grid_backg,
					 &frame_backg,1,1,1 ));

  if ( nb_raw_frames == 1 ) {
    char * nocrh_tag = NULL ;

    nocrh_tag = xsh_stringcat_any("NOCRH_",
				     xsh_instrument_arm_tostring(instrument),
				     (void*)NULL) ;
    xsh_msg( "Remove crh (single frame)" ) ;
    check( clean_frame = xsh_remove_crh_single( rmbkg,
					       instrument,NULL,
					       crh_single_par,
					       nocrh_tag ) ) ;
    XSH_FREE( nocrh_tag ) ;
  }
  else {
      clean_frame = cpl_frame_duplicate( rmbkg) ;
  }

  xsh_msg( "---Divide by flat" ) ;
  sprintf(div_tag,"%s_DIV_FF_%s",
	  rec_prefix,xsh_instrument_arm_tostring(instrument)) ;

  check( flat_method = xsh_parameters_get_string( parameters, RECIPE_ID,
    "flat-method"));
    
  xsh_msg("method %s", flat_method);

  if ( strcmp( flat_method, "master") == 0){
    check( div_frame = xsh_divide_flat( clean_frame, master_flat, 
      div_tag, instrument));
  }
  else{
    xsh_msg("---Create blaze image");
    check( blaze_frame = xsh_blaze_image( master_flat, order_tab_edges,
     instrument));
    check( div_frame = xsh_divide_by_blaze( clean_frame, 
      blaze_frame, instrument));
  }
  
  

  xsh_msg( "---Rectify ifu");
  rect_frameset_eso=cpl_frameset_new();
  rect_frameset_tab=cpl_frameset_new();
  check( rect_frameset = xsh_rectify_ifu( div_frame, order_tab_edges,
					   wavetab_frameset,
                                           nshiftifu_frameset,
					   model_config_frame,
					   instrument, rectify_par,
					   spectral_format,
					   slitmap_frame, &rect_frameset_eso, 
					   &rect_frameset_tab,rec_prefix ));


  check( loc_table_frameset = xsh_localize_obj_ifu( rect_frameset, NULL,
						      instrument,
						      loc_obj_par, NULL));
  xsh_msg( "Merge orders with 2D frame" ) ;
  check( res_2D_frameset = xsh_merge_ord_ifu( rect_frameset,instrument,
					      merge_par,rec_prefix ));
  
  xsh_msg( "Build data cube");
  /* Building 3D (data cube) */
  check( data_cube = xsh_cube( res_2D_frameset, instrument, rec_prefix));

  xsh_msg( "Saving Products for IFU" ) ;
 
  for( i = 0 ; i<3 ; i++ ) {
    cpl_frame * rec_frame = NULL ;
    cpl_frame * res2d_frame = NULL ;

    check( rec_frame = cpl_frameset_get_frame( rect_frameset_eso, i ) ) ;
    check( xsh_add_product_image( rec_frame, frameset, parameters,
				  RECIPE_ID, instrument,NULL));

    check( res2d_frame = cpl_frameset_get_frame( res_2D_frameset, i ) ) ;
    check( xsh_add_product_pre( res2d_frame, frameset, parameters,
				RECIPE_ID, instrument));
  }

  check( xsh_add_product_pre_3d( data_cube, frameset, parameters,
				 RECIPE_ID, instrument));

  name=cpl_frame_get_filename(data_cube);
  plist=cpl_propertylist_load(name,0);
  naxis2=xsh_pfits_get_naxis2(plist);
  xsh_free_propertylist(&plist);
  check( qc_trace_frame=xsh_cube_qc_trace_window(data_cube,
                                                   instrument,tag,rec_prefix,
                                                   save_size+1,
                                                   naxis2-save_size,
                                                   peack_search_hsize,
                                                   method,0));


#if 1

  check( xsh_add_product_pre( rmbias, frameset, parameters, 
    RECIPE_ID, instrument));

  check( xsh_add_product_image( rmbkg, frameset, parameters, 
				RECIPE_ID, instrument,NULL));

  check( xsh_add_product_image( div_frame, frameset, parameters, 
                                RECIPE_ID, instrument,NULL));

  if(qc_trace_frame) {
    check( xsh_add_product_table( qc_trace_frame, frameset,parameters, 
					RECIPE_ID, instrument,NULL));
  }

#endif

  cleanup:
    XSH_REGDEBUG("scired_ifu_stare cleanup");
    xsh_end( RECIPE_ID, frameset, parameters );

    XSH_FREE( rec_prefix);
    XSH_FREE(crh_clipping_par);
    XSH_FREE( backg_par ) ;
    XSH_FREE( crh_single_par ) ;
    XSH_FREE( rectify_par ) ;
    XSH_FREE( loc_obj_par );
    XSH_FREE( extract_par);
    XSH_FREE( stack_par);
 
    xsh_instrument_free(&instrument );
    xsh_free_frameset( &raws);
    xsh_free_frameset( &calib);
    xsh_free_frame( &qc_trace_frame);
    xsh_free_frame( &crhm_frame);
    xsh_free_frame( &slitmap_frame);
    xsh_free_frame( &wavemap_frame);
    xsh_free_frame( &rmbias);
    xsh_free_frame( &rmdark);
    xsh_free_frame( &rmbkg);
    xsh_free_frame( &grid_backg);
    xsh_free_frame( &frame_backg);
    xsh_free_frame( &clean_frame);
    xsh_free_frame( &div_frame);
    xsh_free_frameset( &wavetab_frameset) ;
    xsh_free_frameset( &rect_frameset) ;
    xsh_free_frameset( &loc_table_frameset) ;
    xsh_free_frameset( &shiftifu_frameset);
    xsh_free_frameset( &nshiftifu_frameset);
 
    xsh_free_frameset( &res_2D_frameset) ;
    xsh_free_frameset(&rect_frameset_eso) ;
    xsh_free_frameset(&rect_frameset_tab) ;

    xsh_free_frame( &data_cube ) ;
    xsh_free_frame( &grid_backg ) ;
    xsh_free_frame( &frame_backg ) ;
    xsh_free_frame( &blaze_frame);
    return;
}

/**@}*/
