/*                                                                           *
 *   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:34:01 $
 * $Revision: 1.42 $
 * $Name: not supported by cvs2svn $
 */

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

/*---------------------------------------------------------------------------*/
/**
 * @defgroup xsh_drl_check  DRL check related functions
 * @ingroup xsh_drl
 *
 */
/*---------------------------------------------------------------------------*/


/*----------------------------------------------------------------------------
  Includes
  ----------------------------------------------------------------------------*/
#include <xsh_drl.h>
#include <xsh_drl_check.h>
#include <xsh_pfits.h>
#include <xsh_parameters.h>
#include <xsh_model_utils.h>


cpl_frame*
xsh_check_load_master_bpmap(cpl_frameset* calib, xsh_instrument* inst,
    const char* rec_id) {
  cpl_frame* bpmap = NULL;
  cpl_frame* bpmap_nl = NULL;
  cpl_frame* bpmap_rp = NULL;
  cpl_frame* bp_nl_frame = NULL;
  cpl_frame* frm = NULL;

  cpl_propertylist* plist = NULL;
  cpl_image* image = NULL;
  cpl_frameset* set=NULL;

  char tag_ou[256];
  char name[256];
  const char* bp_nl_name;

  int naxis1 = 0;
  int binx = 0;
  int i=0;
  int sz=0;
  int is_pre=0;
  int mode_or=1;
  XSH_ARM the_arm = XSH_ARM_NIR;

  /* define expected output frame tag with (coadded) BP map info */
  sprintf(tag_ou, "%s_%s", XSH_BP_MAP, xsh_instrument_arm_tostring(inst));

  /* define expected input frame tag that provides BP map info from 3rd extension
   * REMOVED as 3rd extension of image frame should not contribute to BP map at this stage
  if (strcmp(rec_id, "xsh_mbias") == 0) {
  } else if (strcmp(rec_id, "xsh_mdark") == 0 ||
             strcmp(rec_id, "xsh_predict") == 0 ||
             strcmp(rec_id, "xsh_orderpos") == 0 ||
             strcmp(rec_id, "xsh_mflat") == 0) {
    if( the_arm != XSH_ARM_NIR ){
      sprintf(tag_in, "%s_%s", XSH_MASTER_BIAS,
	      xsh_instrument_arm_tostring(inst));
    } 

  } else {
    sprintf(tag_in, "%s_%s", XSH_MASTER_FLAT,
        xsh_instrument_arm_tostring(inst));
  }
  */

  set=cpl_frameset_new();
  /* search for reference pix BP map */
  if ((bpmap_rp = xsh_find_frame_with_tag(calib, XSH_BP_MAP_RP, inst))
      != NULL) {
    xsh_msg("%s provided", XSH_BP_MAP_RP);
     cpl_frameset_insert(set,cpl_frame_duplicate(bpmap_rp));
  }

  /* search for NL BP map */
  if (NULL == (bp_nl_frame = xsh_find_frame_with_tag(calib, XSH_BP_MAP_NL, inst))) {
    xsh_msg("%s not provided", XSH_BP_MAP_NL);
  } else {
    /* if BP_NL map comes from detmon recipe we may need to adjust its format */
    bp_nl_name = cpl_frame_get_filename(bp_nl_frame);
    plist = cpl_propertylist_load(bp_nl_name, 0);
    naxis1 = xsh_pfits_get_naxis1(plist);
    the_arm = xsh_instrument_get_arm(inst);

    if (the_arm != XSH_ARM_NIR) {
      binx = xsh_pfits_get_binx(plist);
    }
    if (the_arm == XSH_ARM_UVB) {
      if ((naxis1 == 2144 && binx == 1) || (naxis1 == 1072 && binx == 2)) {
        bpmap_nl = xsh_bpmap_2pre(bp_nl_frame, XSH_BP_MAP_NL, inst);
        is_pre=1;
      }
    } else if (the_arm == XSH_ARM_VIS) {
      if ((naxis1 == 2106 && binx == 1) || (naxis1 == 1053 && binx == 2)) {
        bpmap_nl = xsh_bpmap_2pre(bp_nl_frame, XSH_BP_MAP_NL, inst);
        is_pre=1;
      }
    } else if (the_arm == XSH_ARM_NIR) {
      if (naxis1 == 2048) {
        bpmap_nl = xsh_bpmap_2pre(bp_nl_frame, XSH_BP_MAP_NL, inst);
        is_pre=1;
      }
    }
    if(!is_pre){
      bpmap_nl=cpl_frame_duplicate(bp_nl_frame);
    }
    cpl_frameset_insert(set,cpl_frame_duplicate(bpmap_nl));
    xsh_free_frame(&bpmap_nl);
  }

  /* search for 3rd ext BP map
  if (tag_in != NULL) {
    if ((frm = cpl_frameset_find(calib, tag_in)) != NULL) {
      xsh_msg("%s provided", tag_in);
      frm_name = cpl_frame_get_filename(frm);
      bpmap_ima = cpl_image_load(frm_name, CPL_TYPE_INT, 0, 3);
      bpmap_3rd = cpl_frame_new();
      sprintf(bpmap_name, "%s.fits", tag_ou);
      cpl_image_save(bpmap_ima, bpmap_name, XSH_PRE_QUAL_BPP, plist, CPL_IO_DEFAULT);
      cpl_frame_set_filename(bpmap_3rd, bpmap_name);
      cpl_frame_set_type(bpmap_3rd, CPL_FRAME_TYPE_IMAGE);
      cpl_frame_set_group(bpmap_3rd, CPL_FRAME_GROUP_CALIB);
      cpl_frame_set_level(bpmap_3rd, CPL_FRAME_LEVEL_FINAL);
      cpl_frameset_insert(set,cpl_frame_duplicate(bpmap_3rd));
    }
  }
  */

  /* now we combine all BP contributes */
  sz=cpl_frameset_get_size(set);
  if (sz > 0) {
    bpmap = cpl_frame_duplicate(cpl_frameset_get_frame(set, 0));
    for(i=1;i<sz;i++) {
      frm=cpl_frameset_get_frame(set,i);
      xsh_badpixelmap_coadd(bpmap, frm,mode_or);
    }
  }

  /* save the result for QC */
  if (bpmap != NULL) {
    image = cpl_image_load(cpl_frame_get_filename(bpmap), CPL_TYPE_INT, 0, 0);
    xsh_free_propertylist(&plist);
    plist = cpl_propertylist_load(cpl_frame_get_filename(bpmap), 0);
    sprintf(name, "%s.fits", tag_ou);
    xsh_pfits_set_pcatg(plist, tag_ou);
    cpl_image_save(image, name, XSH_PRE_DATA_BPP, plist, CPL_IO_DEFAULT);
    cpl_frame_set_tag(bpmap, tag_ou);
    cpl_frame_set_filename(bpmap, name);
    xsh_add_temporary_file(name);
  }

  xsh_free_image(&image);
  xsh_free_propertylist(&plist);
  xsh_free_frameset(&set);

  return bpmap;
}
/*----------------------------------------------------------------------------*/
/**
  @brief Check function to get wave and slit maps
  @param disp_tab_frame dispersion table frame
  @param order_tab_edges order edge table
  @param crhm_frame      frame CRH corrected
  @param model_config_frame model cfg frame
  @param calib           calibration frame list
  @param instrument      instrument setting arm and lamp
  @param do_computemap   switch parameter to compute por not the slit/wave maps
  @param recipe_use_model are we using the model cfg? REALLY NEEDED?
  @param rec_prefix       recipe prefix
  @param wavemap_frame   wavemap frame
  @param slitmap_frame   slitmap frame
  @return
*/
/*----------------------------------------------------------------------------*/
void xsh_check_get_map( cpl_frame *disp_tab_frame, cpl_frame *order_tab_edges,
  cpl_frame *crhm_frame, cpl_frame *model_config_frame, cpl_frameset *calib, 
  xsh_instrument *instrument, int do_computemap, int recipe_use_model,
  const char *rec_prefix,
  cpl_frame **wavemap_frame, cpl_frame **slitmap_frame)
{
  char wave_map_tag[256];
  char slit_map_tag[256];

  if ( do_computemap){
    if ( recipe_use_model){
      int found_temp= CPL_TRUE;

      xsh_msg( "Compute with MODEL the wave map and the slit map");
      check( xsh_model_temperature_update_frame( &model_config_frame,
        crhm_frame, instrument,&found_temp));
      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_create_model_map( model_config_frame, instrument,
        wave_map_tag,slit_map_tag, wavemap_frame, slitmap_frame,0));
    }
    else{
      xsh_msg("Compute with POLY 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{
    cpl_frame *tmp = NULL;

    xsh_msg( "Get the wave map and the slit map");
    tmp = xsh_find_slitmap( calib, instrument);
    check_msg( *slitmap_frame =  cpl_frame_duplicate( tmp),"If compute-map is set to FALSE you must provide a SLIT_MAP_ARM frame in input");
    tmp = xsh_find_wavemap( calib, instrument);
    check_msg( *wavemap_frame =  cpl_frame_duplicate( tmp),"If compute-map is set to FALSE you must provide a SLIT_MAP_ARM frame in input");
  }

  cleanup:
    return;
}
/*----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/**
  @brief Check function
  @param raws input raw frames
  @param ftag file tag
  @param crh_clipping_par parameter controlling CRH
  @param instr instrument arm and lamp setting
  @param lista output imagelist
  @param listb output image
  @return frame cleaned from CRHs via stacking and kappa sigma clip
*/
/*----------------------------------------------------------------------------*/
cpl_frame* xsh_check_remove_crh_multiple( cpl_frameset* raws,
  const char *ftag, xsh_stack_param* stack_par,xsh_clipping_param *crh_clipping_par,
  xsh_instrument* instr,cpl_imagelist ** lista, cpl_image** listb)
{
  int size_raw_frameset =0;
  cpl_frame *result = NULL;

  XSH_ASSURE_NOT_NULL( ftag);

  check( size_raw_frameset = cpl_frameset_get_size( raws));

  if ( size_raw_frameset >= 2 ) {
    xsh_msg( "---Remove crh (multiple frames)");
    check_msg( result = xsh_remove_crh_multiple( raws,ftag, stack_par, crh_clipping_par,instr, lista, listb,1),
      "Error in xsh_remove_crh");

  }
  else {
    check( result = cpl_frame_duplicate(cpl_frameset_get_frame( raws,0)));
  }
  cleanup:
    return result;
}
/*----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/**
  @brief Check function to subtract bias
  @param crhm_frame input frame (eventually cleaned by CRH)
  @param master_bias master bias
  @param instrument instrument arm and lamp setting
  @param prefix file prefix
  @param pre_overscan_corr correct for overscan?
  @return
*/
/*----------------------------------------------------------------------------*/ 
cpl_frame* xsh_check_subtract_bias( cpl_frame *crhm_frame, 
				     cpl_frame *master_bias, 
				     xsh_instrument *instrument,
				     const char* prefix,
				     const int pre_overscan_corr,const int save_tmp)
{
  cpl_frame *result = NULL;

  XSH_ASSURE_NOT_NULL( crhm_frame);
  XSH_ASSURE_NOT_NULL( instrument);
  XSH_ASSURE_NOT_NULL( prefix);

  if ( xsh_instrument_get_arm(instrument) == XSH_ARM_NIR ) {
    char rmbias_tag[256];

    sprintf( rmbias_tag, "%s_%s_%s", prefix,"ON",
            xsh_instrument_arm_tostring(instrument));
    /* No bias for NIR */
    check( result = cpl_frame_duplicate( crhm_frame));
    cpl_frame_set_tag( result, rmbias_tag);
  }
  else {
    /* UVB and VIS arm */
    xsh_msg("---Subtract bias");
    if( master_bias != NULL) {
      /* subtract bias */
      check( result = xsh_subtract_bias( crhm_frame, master_bias, 
					  instrument, prefix,
					  pre_overscan_corr,save_tmp));
    } 
    else {
      result = cpl_frame_duplicate( crhm_frame);
    }
  }
  cleanup:
    return result;
}
/*----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/**
  @brief Check function for dark subtraction
  @param rmbias_frame input frame 
  @param master_dark master dark
  @param instrument instrument arm and lamp setting
  @param prefix file prefix
  @return
*/
/*----------------------------------------------------------------------------*/
cpl_frame* xsh_check_subtract_dark( cpl_frame *rmbias_frame,
  cpl_frame *master_dark, xsh_instrument *instrument, const char* prefix)
{
  cpl_frame *result = NULL;
  char result_name[256];

  XSH_ASSURE_NOT_NULL( rmbias_frame);
  XSH_ASSURE_NOT_NULL( instrument);
  XSH_ASSURE_NOT_NULL( prefix);

  if(master_dark != NULL) {
    xsh_msg( "---Subtract dark");
    sprintf( result_name, "%s_DARK.fits", prefix);
    check( result = xsh_subtract_dark( rmbias_frame, master_dark,
      result_name, instrument));
    xsh_add_temporary_file(result_name);
  }
  else {
    result = cpl_frame_duplicate( rmbias_frame);
  }

  cleanup:
    return result;
}
/*----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/**
  @brief
    Check function
  @param do_flatfield check if flat field has to be applied
  @param clean_frame input frame cleaned by CRHs
  @param master_flat input master flat field
  @param instrument structure containing instrument arm and lamp setting
  @param prefix file prefix

  @return
*/
/*----------------------------------------------------------------------------*/
cpl_frame* xsh_check_divide_flat( int do_flatfield, cpl_frame *clean_frame,
  cpl_frame *master_flat, xsh_instrument *instrument, const char* prefix)
{
  cpl_frame *result = NULL;
  char result_tag[256];

  XSH_ASSURE_NOT_NULL( clean_frame);
  XSH_ASSURE_NOT_NULL( instrument);
  XSH_ASSURE_NOT_NULL( prefix);

  if( do_flatfield == CPL_TRUE) {
    xsh_msg( "---Divide flat");
    sprintf( result_tag, "%s_DIVFF_%s", prefix,
      xsh_instrument_arm_tostring(instrument)) ;

    check( result = xsh_divide_flat( clean_frame, master_flat, 
      result_tag, instrument));
  }
  else{
    check( result = cpl_frame_duplicate( clean_frame));
  }
  cleanup:
    return result;
}
/*----------------------------------------------------------------------------*/


/*----------------------------------------------------------------------------*/
/**
  @brief Check function
  @param nb_raws_frame number of raw frames
  @param subsky_frame frame sky subtracted
  @param crh_single_par parameters to control CRH (single frame) subtraction
  @param instrument instrument arm and lamp setting
  @param prefix file prefix
  @return
*/
/*----------------------------------------------------------------------------*/
cpl_frame* xsh_check_remove_crh_single( int nb_raws_frame, 
  cpl_frame *subsky_frame, xsh_remove_crh_single_param *crh_single_par,
  xsh_instrument *instrument, const char* prefix)
{
  char result_tag[256];
  char result_name[256];
  cpl_frame *result = NULL;
  
  XSH_ASSURE_NOT_NULL( subsky_frame);
  XSH_ASSURE_NOT_NULL( crh_single_par);
  XSH_ASSURE_NOT_NULL( instrument);
  XSH_ASSURE_NOT_NULL( prefix);

  if ( nb_raws_frame == 1 && crh_single_par->nb_iter > 0) {
    xsh_msg( "---Remove crh (single frame)");
    sprintf( result_tag, "%s_NOCRH_%s", prefix,
      xsh_instrument_arm_tostring(instrument));
    sprintf( result_name, "%s.fits",result_tag);
    xsh_add_temporary_file(result_name);

    check( result = xsh_remove_crh_single( subsky_frame,
      instrument, NULL,crh_single_par, result_tag));
  }
  else {
    check( result = cpl_frame_duplicate( subsky_frame));
  }

  cleanup:
    return result;
}
/*----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/**
  @brief Check function sky subtraction on single frame
  @param[in] do_subsky do sky subtraction?
  @param[in] src_frame source frame
  @param[in] ordertabedges_frame order edge table
  @param[in] slitmap_frame slit map frame
  @param[in] wavemap_frame wave map frame
  @param[in] loctab_frame localization table
  @param[in] masterflat_frame master flat frame
  @param[in] definedbreakpoints_frame frame defining break points order by order
  @param[in] instrument instrument arm and lamp setting
  @param[in] nbkpts number of break points
  @param[in] sky_par parameters controlling sky subtraction
  @param[out] sky_spectrum output sky spectrum 1D
  @param[out] sky_spectrum_eso output sky spectrum ESO format
  @param[out] sky_img sky image for QC
  @param[in] prefix file prefix
  @return frame corrected for sky background in DRL format
*/
/*----------------------------------------------------------------------------*/

cpl_frame* xsh_check_subtract_sky_single( int do_subsky,
                                          cpl_frame *src_frame,
                                          cpl_frame *ordertabedges_frame,
                                          cpl_frame *slitmap_frame,
                                          cpl_frame *wavemap_frame,
                                          cpl_frame *loctab_frame,
                                          cpl_frame *definedbreakpoints_frame,
                                          xsh_instrument *instrument,
                                          int nbkpts,
                                          xsh_subtract_sky_single_param *sky_par,
                                          cpl_frame* ref_sky_list,
                                          cpl_frame* sky_orders_chunks,
                                          cpl_frame **sky_spectrum,
                                          cpl_frame **sky_spectrum_eso,
                                          cpl_frame **sky_img,
                                          const char *prefix,
                                          const int clean_tmp)
{
    char result_tag[256];
    char result_name[256];
    cpl_frame *result = NULL;

  XSH_ASSURE_NOT_NULL( src_frame);
 
  if ( do_subsky == CPL_TRUE){
    xsh_msg("---Sky subtraction (single frame)");
    check( result = xsh_subtract_sky_single( src_frame, ordertabedges_frame,
      slitmap_frame, wavemap_frame, loctab_frame,ref_sky_list,sky_orders_chunks,
      definedbreakpoints_frame, instrument, nbkpts, sky_par, sky_spectrum,
					     sky_spectrum_eso, prefix,clean_tmp));
   sprintf( result_tag,"%s_SKY_%s", prefix, 
      xsh_instrument_arm_tostring(instrument));
   sprintf( result_name,"%s.fits", result_tag);
   check( *sky_img = xsh_save_sky_model( src_frame, result, result_tag,
					 instrument));
   if(strstr(result_name,"TMPSKY")!=NULL) {
     xsh_add_temporary_file(result_name);
   }
  } 
  else{
     xsh_msg("[No sky subtraction]");
    check( result = cpl_frame_duplicate( src_frame));
  }

    if ( do_subsky == CPL_TRUE){

        XSH_ASSURE_NOT_NULL_MSG( src_frame,"Required science frame is missing");
        XSH_ASSURE_NOT_NULL_MSG( ordertabedges_frame,"Required order table frame is missing");
        XSH_ASSURE_NOT_NULL_MSG( slitmap_frame, "Required slitmap frame is missing, provide it or set compute-map to TRUE");
        XSH_ASSURE_NOT_NULL_MSG( wavemap_frame,"Required wavemap frame is missing");
        XSH_ASSURE_NOT_NULL_MSG( instrument,"Instrument setting undefined");
        XSH_ASSURE_NOT_ILLEGAL( nbkpts > 1);
        XSH_ASSURE_NOT_NULL_MSG( sky_par,"Undefined input sky parameters");
        //XSH_ASSURE_NOT_NULL_MSG(ref_sky_list,"Null input reference sky line list");
        XSH_ASSURE_NOT_NULL( prefix);

        xsh_msg("---Sky subtraction (single frame)");
        xsh_free_frame(&result);
        check( result = xsh_subtract_sky_single( src_frame, ordertabedges_frame,
                        slitmap_frame, wavemap_frame, loctab_frame,ref_sky_list,
                        sky_orders_chunks,
                        definedbreakpoints_frame, instrument, nbkpts, sky_par,
                        sky_spectrum, sky_spectrum_eso, prefix,clean_tmp));
        sprintf( result_tag,"%s_SKY_%s", prefix,
                 xsh_instrument_arm_tostring(instrument));
        sprintf( result_name,"%s.fits", result_tag);
        xsh_free_frame(sky_img);
        check( *sky_img = xsh_save_sky_model( src_frame, result, result_tag,
                        instrument));
        if(strstr(result_name,"TMPSKY")!=NULL) {
            xsh_add_temporary_file(result_name);
        }
    }
    else{
        xsh_msg("[No sky subtraction]");
        xsh_free_frame(&result);
        check( result = cpl_frame_duplicate( src_frame));
    }

    cleanup:
    return result;
}
/*----------------------------------------------------------------------------*/


/*----------------------------------------------------------------------------*/
/**
  @brief Check AFC frame
  @param check_flag If TRUE do the check
  @param model_frame Model frame
  @param sci_frame Science frame
  @param wave_frameset Wave solution frameset
  @param order_tab_frame Order Table frame
  @param disp_tab_frame Dispersion solution frame
  @param instrument Instrument structure
*/
/*----------------------------------------------------------------------------*/
void xsh_check_afc( int check_flag, cpl_frame *model_frame, 
  cpl_frame *sci_frame, cpl_frameset *wave_frameset, 
  cpl_frame *order_tab_frame, cpl_frame *disp_tab_frame, 
  xsh_instrument *instrument)
{
  int i;
  
  if (check_flag) {
     if( model_frame!=NULL) {
       check(xsh_frame_check_model_cfg_is_afc_corrected(model_frame));
       check(xsh_frame_check_model_cfg_is_proper_for_sci(model_frame,
         sci_frame,instrument));
     } 
     else {
      for(i=0; i< 3; i++){
	cpl_frame *wavesol_frame = NULL;
	  
	wavesol_frame = cpl_frameset_get_frame( wave_frameset, i);
        check(xsh_frame_check_model_cfg_is_afc_corrected(wavesol_frame));
        check(xsh_frame_check_model_cfg_is_proper_for_sci(wavesol_frame,
                                                       sci_frame,instrument));
      }
      check(xsh_frame_check_model_cfg_is_afc_corrected( order_tab_frame));
      check(xsh_frame_check_model_cfg_is_proper_for_sci( order_tab_frame,
                                                       sci_frame,instrument));      
      if ( disp_tab_frame != NULL){
        check(xsh_frame_check_model_cfg_is_afc_corrected( disp_tab_frame));
        check(xsh_frame_check_model_cfg_is_proper_for_sci( disp_tab_frame,
                                                       sci_frame,instrument));	
      }
    }
  }
  cleanup:
    return;
}
/*----------------------------------------------------------------------------*/

#if 0
void xsh_check_localize_and_nocrh( int nb_frames, loc_obj_par
  /* Create the localization */
  if (loc_obj_par->method == LOC_MANUAL_METHOD){
    check( loc_table_frame = xsh_localize_obj( NULL,
      instrument, loc_obj_par, NULL, NULL));
  }
  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 localize auto");
     xsh_msg("Sky will be put back later");

    sprintf(sky_tag,"%s_TMP_SKY_%s",rec_prefix,
            xsh_instrument_arm_tostring(instrument));

    check( sub_sky_frame = xsh_subtract_sky_single( rmbkg, order_tab_edges,
                                                     slitmap_frame, wavemap_frame, 
                                                     NULL,
                                                     single_frame_sky_sub_tab_frame,
                                                     instrument, 
                                                     sub_sky_nbkpts1, sky_par,
                                                     &sky_frame,
                                                    &sky_frame_eso,
                                                    sky_tag));



 

     /* to monitor quality of SKY model 
        we subtract to object before sky subtraction (flatfielded)
        the frame after sky subtraction. This should give only the sky
        (if the object is well masked)
     */
    sky_frame_ima=xsh_save_sky_model(rmbkg,sub_sky_frame,sky_tag,instrument,decode_bp);
    


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

        /* rectify */ 
  
        check( rect_frame = xsh_rectify( sub_sky_frame, order_tab_edges,
                                         wave_tab, model_config_frame, 
                                         instrument, rectify_par,
                                         spectralformat_frame, disp_tab_frame, 
                                         rec_name, NULL, NULL,rec_prefix));

        /* localize */
        check( loc_table_frame = xsh_localize_obj( rect_frame, instrument,
                                                   loc_obj_par, NULL, NULL));
     }
     /* Remove COSMICS single */
     check( clean_frame = xsh_check_remove_crh_single( nb_raw_frames, sub_sky_frame,
       crh_single_par, wavemap_frame, instrument, rec_prefix));

     /* We put back the SKY before doing flat field and 
        proper sky subtraction */  
     {
     char * obj_nocrh_tag = NULL ;
     char * obj_nocrh_name = NULL ;

     obj_nocrh_tag = xsh_stringcat_any("OBJ_AND_SKY_NOCRH_",
                                       xsh_instrument_arm_tostring(instrument),
                                       (void*)NULL) ;
     obj_nocrh_name = xsh_stringcat_any("OBJ_AND_SKY_NOCRH_",
                                        xsh_instrument_arm_tostring(instrument),
                                        ".fits",(void*)NULL) ;

     check( pre_sci = xsh_pre_load( clean_frame, instrument));
    
     strcpy(sky_name,cpl_frame_get_filename(sky_frame_ima));
     check(sky_image=cpl_image_load(sky_name,CPL_TYPE_FLOAT,0,0));
     check(cpl_image_add(pre_sci->data,sky_image));

     check(clean_obj=xsh_pre_save(pre_sci, obj_nocrh_name,  obj_nocrh_tag, 1));
     
     XSH_FREE( obj_nocrh_tag ) ;
     XSH_FREE( obj_nocrh_name ) ;
     xsh_pre_free( &pre_sci);
     }


  } else {
     /* LOcalize manual && no CRH SINGLE */
     check( clean_obj=cpl_frame_duplicate(rmbkg));
  }
#endif



/**@}*/
