/*                                                                            *
 *   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-01-30 10:22:50 $
 * $Revisieon: 1.10 $
 *
*/

#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.h>
#include <xsh_utils_ifu.h>
#include <xsh_utils_scired_slit.h>
#include <xsh_utils_image.h>
#include <xsh_model_utils.h>
#include <xsh_model_io.h>
#include <xsh_msg.h>
/* DFS functions */
#include <xsh_dfs.h>
#include <xsh_pfits.h>
/* DRL functions */
#include <xsh_drl.h>
#include <xsh_drl_check.h>
#include <xsh_model_arm_constants.h>
/* Library */
#include <cpl.h>
/* CRH Remove */

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

#define RECIPE_ID "xsh_scired_ifu_stare"
#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_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 IFU stare exposures and build a 3D cube";

static char xsh_scired_ifu_stare_description[] =
"This recipe reduce science IFU stare exposures with 3D cube generation\n\
Input Frames : \n\
  - A set of n Science frames ( n == 1 or >=3, \
    Tag = OBJECT_IFU_STARE_UVB)\n\
  - A spectral format table frame (Tag = SPECTRAL_FORMAT_TAB_arm)\n\
  - [UVB,VIS] A master bias frame (Tag = MASTER_BIAS_arm)\n\
  - A master dark frame (Tag = MASTER_DARK_arm)\n\
  - A master flat frame (Tag = MASTER_FLAT_IFU_arm)\n\
  - An order edges table frame(Tag = ORDER_TAB_EDGES_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] 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";


/*-----------------------------------------------------------------------------
  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;
  xsh_clipping_param crh_clip_param = {5.0, 5, 0.7, 0,0.3};
  /* First param (conv_kernel) should be initialized correctly ! */
  xsh_rectify_param rectify = { "tanh",
                                CPL_KERNEL_DEFAULT, 2,
                                -1., 
                                -1.,
				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, 1, 0, LOC_GAUSSIAN_METHOD, 0, 0.5, 2.0, 3};
  */
  /* 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));

  /* 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 )) ;
  */
  /* 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    Rescale input parameters for binning
  @param    raws    the frameset
  @param    backg   the inter-order background parameters

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

}

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

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

  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[4] = {XSH_OBJECT_IFU_STARE,XSH_SKY_IFU,
                                XSH_STD_TELL_IFU_STARE,
                                XSH_STD_FLUX_IFU_STARE};

  int recipe_tags_size = 4;

  /* 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 *spectral_format = NULL;
  cpl_frame *ifu_cfg_tab_frame = NULL ;
  cpl_frame *ifu_cfg_cor_frame = 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 *model_config_frame = NULL ;
  cpl_frame *wavemap = NULL ;
  cpl_frame *slitmap = NULL ;
  cpl_frame *disp_tab_frame = NULL;

  /* Parameters */
  xsh_background_param *backg_par = NULL;
  xsh_rectify_param *rectify_par = NULL ;
  xsh_stack_param* stack_par=NULL;

  int do_compute_map = 0;

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

  xsh_instrument* instrument = NULL;
  int nb_raw_frames;

  /* Intermediate frames */
  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 *div_frame = NULL ; /**< Output of xsh_divide_flat */

  /* Output Frames (results)*/
  cpl_frame* grid_backg=NULL;
  cpl_frame* frame_backg=NULL;

  const char* ftag=NULL;
  char rec_prefix[256];
  //cpl_image* crh_ima=NULL;
  //cpl_frame* crh_frm=NULL;
  char tag[256];
  char name[256];
  cpl_frame* wavesol=NULL;
  cpl_frame* order_tab_edges_frame=NULL;

  char wave_map_tag[256];
  char slit_map_tag[256];
  char* prefix=NULL;
  int pre_overscan_corr=0;
  cpl_frame* ifu_sky_map=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);
  /**************************************************************************/
  /* Recipe frames */
  /**************************************************************************/

  /* 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( nb_raw_frames == 1 || nb_raw_frames >= 3 ) ;

  if(nb_raw_frames>1) {
    check(xsh_frameset_check_uniform_exptime(raws,instrument));
  }

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


  prefix=xsh_set_recipe_file_prefix(raws,"xsh_scired_ifu_stare");
  check(strcpy(rec_prefix,(const char*)prefix));
  XSH_FREE(prefix);
  xsh_msg("ok1");
  check(xsh_ifu_stare_get_calibs(calib, instrument, &spectral_format, &master_bias,
                           &master_dark, &master_flat, &order_tab_edges,
                           &model_config_frame, &bpmap, &wavemap, &slitmap,
                           &ifu_cfg_tab_frame, &ifu_cfg_cor_frame, &wavesol,
                           RECIPE_ID, &recipe_use_model, pre_overscan_corr));


  xsh_msg("ok2");
  /**************************************************************************/
  /* Recipe parameters */
  /**************************************************************************/
  recipe_use_model = ( model_config_frame != NULL);

  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( do_compute_map = xsh_parameters_get_boolean( parameters, RECIPE_ID,
    "compute-map"));

  check( check_afc = xsh_parameters_get_boolean( parameters, RECIPE_ID,
    "check-afc"));

  check( do_trace_obj = xsh_parameters_get_boolean( parameters, RECIPE_ID,
    "trace-obj"));

  if ( do_compute_map && 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));


  /**************************************************************************/
  /* Recipe code */
  /**************************************************************************/
  /* prepare RAW frames in XSH format */
  xsh_msg( "---Prepare raws frames");
  check( xsh_prepare( raws, bpmap, master_bias, XSH_OBJECT_IFU_STARE,
		      instrument,pre_overscan_corr,CPL_TRUE));

  /* Removing Cosmic Rays (if more than 2 frames)
   Output frame in PRE format */
  if ( nb_raw_frames >= 3 ) {
    xsh_msg( "---Remove cosmics");

    ftag=XSH_GET_TAG_FROM_ARM(XSH_SLIT_STARE_REMOVE_CRH,instrument);
    check_msg( crhm_frame = xsh_remove_crh_multiple( raws,
						   ftag,stack_par,NULL,
						     instrument, NULL,NULL,0 ),
	       "Error in xsh_remove_crh" ) ;
  }
  else {
    /* Only one frame in raws frameset, get it (it's first of course !) */
    check( crhm_frame = cpl_frame_duplicate(cpl_frameset_get_frame( raws,0 )));
  }
  xsh_msg( "created %s", cpl_frame_get_filename( crhm_frame));


  if (recipe_use_model){
       int found_temp=true;
       xsh_msg("correct for temperature");
       check(xsh_model_temperature_update_frame(&model_config_frame,crhm_frame,
                                                instrument,&found_temp));
  }

  if ( do_compute_map){
     check(xsh_mode_set(instrument,XSH_MODE_IFU));

    if (recipe_use_model){


       sprintf(wave_map_tag,"%s_%s",rec_prefix,XSH_WAVE_MAP_MODEL);
       sprintf(slit_map_tag,"%s_%s",rec_prefix,XSH_SLIT_MAP_MODEL);
       check( xsh_create_model_map( model_config_frame, instrument,
                                    wave_map_tag,slit_map_tag, 
                                    &wavemap, &slitmap,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, &slitmap,rec_prefix));
    }
    cpl_frameset_insert( calib, wavemap);
    cpl_frameset_insert( calib, slitmap);
  }
  else{
    check( wavemap = xsh_find_wavemap( calib, instrument));
    slitmap = xsh_find_slitmap(calib, instrument);
  }

  /* NIR arm */
  check( rmbias = xsh_check_subtract_bias( crhm_frame, master_bias, 
					    instrument, rec_prefix,
                                           pre_overscan_corr,0));
 
  xsh_add_temporary_file(cpl_frame_get_filename(rmbias));
  /**************************************************************************/
  /* 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,
                                                          rmbias,instrument));
     } else {
        check(xsh_frame_check_model_cfg_is_afc_corrected(wavesol));
        check(xsh_frame_check_model_cfg_is_proper_for_sci(wavesol,
                                                          rmbias,instrument));
     }
  }

  /* Subtract Dark */
  if ( master_dark != NULL ) {
    xsh_msg( "---Subtract_dark");
    sprintf(name, "%s_DARK_%s.fits", 
           rec_prefix,xsh_instrument_arm_tostring(instrument));
    check( rmdark = xsh_subtract_dark(rmbias, master_dark,
                                      name,instrument));
  }
  else {
    xsh_msg( "No Master Dark" ) ;
    check( rmdark = cpl_frame_duplicate( rmbias ) ) ;
  }
  xsh_free_frame(&rmbias);


  /* subtract background */
  xsh_msg("---Subtract_background");
  check( rmbkg = xsh_subtract_background( rmdark,
    order_tab_edges, backg_par, instrument, rec_prefix,&grid_backg,
					  &frame_backg,0,0,0 ));
  xsh_free_frame(&rmdark);

  /* divide by */
  xsh_msg("---Do flatfielding");
  sprintf( tag, "%s_FF_%s", 
           rec_prefix,xsh_instrument_arm_tostring(instrument));
  sprintf(name,"%s.fits",tag);
  check( div_frame = xsh_divide_flat( rmbkg, master_flat,
      tag, instrument));
  xsh_add_temporary_file(name);
 
  xsh_free_frame( &rmbkg);

  if(do_trace_obj && do_compute_map) {
     check(xsh_mode_set(instrument,XSH_MODE_IFU));
     check(order_tab_edges_frame = xsh_find_order_tab_edges(calib,instrument));
     check(xsh_mode_set(instrument,XSH_MODE_SLIT));
     check(xsh_ifu_trace_object_calibrate(cpl_frame_get_filename(div_frame),
                                          cpl_frame_get_filename(order_tab_edges_frame),
                                          cpl_frame_get_filename(slitmap),
                                          cpl_frame_get_filename(wavemap)));
  }

  check(xsh_build_ifu_cube(div_frame,ifu_cfg_tab_frame,ifu_cfg_cor_frame,
                           spectral_format,
                           model_config_frame,
                           wavesol,
                           instrument,
                           frameset,
                           parameters,rectify_par,RECIPE_ID,rec_prefix,1));

  if(do_compute_map) {
  check(ifu_sky_map=xsh_build_ifu_map(div_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_instrument_free( &instrument);
  xsh_free_frameset( &raws);
  xsh_free_frameset( &calib);

  xsh_free_frame( &crhm_frame);
  xsh_free_frame(&rmbias);
  xsh_free_frame(&div_frame);
  xsh_free_frame(&rmdark);
  xsh_free_frame( &rmbkg);
  xsh_free_frame( &grid_backg);
  xsh_free_frame( &frame_backg);

  XSH_FREE(stack_par);
  XSH_FREE(backg_par);
  XSH_FREE(rectify_par);

  //xsh_free(&model_config);
  return;
}

/**@}*/
