/*                                                                            *
 *   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-01 12:47:55 $
 * $Revision: 1.157 $
 * $Name: not supported by cvs2svn $
 *
 */

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

/*--------------------------------------------------------------------------*/
/**
 * @defgroup xsh_predict   xsh_predict
 * @ingroup recipes
 *
 * This recipe is used to obtain a first guess dispersion solution and order 
 * table.  It calculates the geometry of the spectral format from a physical 
 *model and compares the predicted line positions to the ones on the 
 *calibration frame
 * See man-page for details.
 */
/*--------------------------------------------------------------------------*/
/**@{*/

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


//#include <xsh_pfits.h>
/* 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_utils_table.h>
#include <xsh_data_resid_tab.h>
/* DRL functions */
#include <xsh_data_order.h>
#include <xsh_drl.h>
#include <xsh_drl_check.h>
#include <xsh_model_kernel.h>
#include <xsh_model_arm_constants.h>


/* Library */
#include <cpl.h>



#include <xsh_data_arclist.h>
/*---------------------------------------------------------------------------
                                Defines
 ---------------------------------------------------------------------------*/

#define RECIPE_ID "xsh_predict"
#define RECIPE_AUTHOR "P.Goldoni, L.Guglielmi, R. Haigron, F. Royer, P. Bristow, D. Bramich, A. Modigliani"
#define RECIPE_CONTACT "amodigli@eso.org"

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

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

static int xsh_predict_create(cpl_plugin *);
static int xsh_predict_exec(cpl_plugin *);
static int xsh_predict_destroy(cpl_plugin *);

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

/*---------------------------------------------------------------------------
                            Static variables
 ---------------------------------------------------------------------------*/
static char xsh_predict_description_short[] =
"Compute a first guess dispersion solution and order table";

static char xsh_predict_description[] =
"This recipe creates a wavelength solution and an order table.\n\
  Input Frames :\n\
    - [UVB, VIS] One RAW frame (Format = RAW, Tag = FMTCHK_arm)\n\
    - [NIR] Two RAW frames ((Format = RAW,  Tag = FMTCHK_arm_ON,\
FMTCHK_arm_OFF)\n\
    - A spectral format table (Format = PRE, Tag = SPECTRAL_FORMAT_TAB_arm)\n\
    - An arc line list (Format = TABLE, Tag = ARC_LINE_LIST_arm)\n\
    - [UVB,VIS,OPTIONAL] A master bias (Format = PRE, Tag = MASTER_BIAS_arm)\n\
    - [UVB,VIS,OPTIONAL] A master dark (Format = PRE, Tag = MASTER_DARK_arm)\n\
    - [OPTIONAL] A reference badpixel map (Format = QUP, Tag = BP_MAP_RP_arm)\n\
    - [OPTIONAL] A non-linear badpixel map (Format = QUP, Tag = BP_MAP_NL_arm)\n\
    - [OPTIONAL] Reference list to monitor line intensity (Tag = ARC_LINE_LIST_INTMON_arm)\n \
    - [poly mode] A theoretical map (Format = TABLE, Tag = THEO_TAB_SING_arm)\n\
    - [physical model mode] A model cfg table (Format = TABLE, Tag = XSH_MOD_CFG_TAB_arm)\n\
  Products : \n\
    - [poly mode] A wavelength solution (Format = TABLE, PRO.CATG = \
WAVE_TAB_GUESS_arm)\n\
    - An order table, PRO.CATG = ORDER_TAB_GUESS_arm\n\
      (if at least degree+1 points are found in each order).\n  \
    - A line identification residual table, PRO.CATG = FMTCHK_RESID_TAB_LINES_arm\n\
    - The bias subtracted formatcheck frame, PRO.CATG = FMTCHK_ON_arm\n\
    - [physical model mode]An optimized model configuration table, PRO.CATG = XSH_MOD_CFG_OPT_FMT_ARM\n\
  Prepare the frames.\n\
  For UVB,VIS :\n\
    Subtract Master Bias.\n\
    Subtract Master Dark\n\
  For NIR:\n\
    Subtract ON OFF\n\
  Compute guess order table and wavelength solution\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_predict_description_short,      /* Short help */
                  xsh_predict_description,            /* Detailed help */
                  RECIPE_AUTHOR,                    /* Author name */
                  RECIPE_CONTACT,                   /* Contact address */
                  xsh_get_license(),                /* Copyright */
                  xsh_predict_create,
                  xsh_predict_exec,
                  xsh_predict_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_predict_create(cpl_plugin *plugin){
  cpl_recipe *recipe = NULL;
  xsh_clipping_param detarc_clip_param = { 2.0, 10, 0.7, 0, 0.3};
  xsh_detect_arclines_param detarc_param = {6, 3, 0, 5, 5, 0, 2, 5.0,
    XSH_GAUSSIAN_METHOD, FALSE};
  char paramname[256];
  cpl_parameter* p=NULL;
  const int ival=DECODE_BP_FLAG_DEF;
  /* 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,ival);
  check( xsh_parameters_pre_overscan( RECIPE_ID, recipe->parameters ) ) ;

 
  /* detect arclines params */
  check(xsh_parameters_detect_arclines_create(RECIPE_ID,recipe->parameters, 
    detarc_param));
  check(xsh_parameters_clipping_detect_arclines_create(RECIPE_ID, 
    recipe->parameters, detarc_clip_param));



  /* Annealing parameter */
  check(  xsh_parameters_new_int( recipe->parameters, RECIPE_ID, 
                                      "model-maxit",1000,
                                  "Number/10 of annealing iterations "
                                  "if in physical model mode."));

  check(  xsh_parameters_new_double( recipe->parameters, RECIPE_ID, 
                                      "model-anneal-factor",1.0,
                                  "Multiplier applied to the automatic "
                                  "parameter ranges (i.e. when scenario!=0). "
				  "For routine operations should be 1.0. "
                                  "(physical model mode)."));

  
  sprintf(paramname,"xsh.%s.%s",RECIPE_ID,"model-scenario");

  /*Scenario descriptions for development use removed so as not to confuse users*/
  check(p=cpl_parameter_new_enum(paramname,CPL_TYPE_INT,
				 "selects preset flag and range combinations "
                                 "appropriate to common scenarios: \n"
/* 				 "-1 - Only the position across the slit and "
 				 "camera focal length are open\n" */
				 " 0 - No scenario, input cfg flags and limits "
				 "used.\n"
				 " 1 - scenario appropriate for the startup "
				 "recipe (large ranges for parameters "
				 "affecting single ph exposures, dist "
				 "coeff fixed).\n"
				 " 2 - Like 1, but includes parameters "
				 "affecting all ph positions.\n"
				 " 3 - Scenario for use in fine tuning cfg "
				 "to match routine single pinhole exposures. "
				 "All parameters affecting 1ph exposures "
				 "except dist coeffs are included and "
				 "parameter ranges are small. (For use by "
				 "predict in 1ph case).\n"
				 " 4 - Like 3 but includes parameters  "
				 "affecting all ph positions (Standard for "
				 "use by predict in 9ph case and 2dmap). \n"
/* 				 " 5 - Like 4 but includes also dist coeffs.\n" 
                                 " 6 - Just dist coeffs (and chipx, chipy).\n"*/
                                 ,RECIPE_ID,3,9,-1,0,1,2,3,4,5,6,8));


  check(cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
				"model-scenario"));
  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_predict_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_predict(recipe->parameters, recipe->frames);

  cleanup:
    if ( cpl_error_get_code() != CPL_ERROR_NONE ) {
      xsh_error_dump(CPL_MSG_ERROR);
      cpl_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_predict_destroy(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;

    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_predict(cpl_parameterlist* parameters, cpl_frameset* frameset)
{
  const char* recipe_tags[1] = {XSH_FMTCHK};
  int recipe_tags_size = 1;
  char tag[256];
  /* RECIPES parameters */
  xsh_clipping_param* detect_arclines_clipping = NULL;
  xsh_detect_arclines_param* detect_arclines_p = NULL;

  /* ALLOCATED locally */
  cpl_frameset* raws = NULL;
  cpl_frameset* calib = NULL;
  cpl_frameset* on = NULL;
  cpl_frameset* off = NULL;
  cpl_frameset* on_off = NULL;
  cpl_frame* predict_rmbias = NULL;
  cpl_frame* predict_rmdark = NULL; 
  xsh_instrument* instrument = NULL;
  int solution_type=XSH_DETECT_ARCLINES_TYPE_MODEL;
  /* Others */
  cpl_frame* model_config_frame = NULL;
  cpl_frame* spectralformat_frame = NULL;
  cpl_frame* bpmap = NULL;
  cpl_frame* master_bias = NULL;
  cpl_frame* master_dark = NULL;
  cpl_frame* theo_tab_sing = NULL;
  cpl_frame* resid_map = NULL;
  cpl_frame* resid_dan = NULL;
  cpl_frame* resid_tab_orders_frame = NULL;
  cpl_frame *wave_tab_guess_frame = NULL;
  cpl_frame *order_tab_recov_frame = NULL;
  cpl_frame* arclines = NULL;
  cpl_frame* clean_arclines = NULL;
  cpl_frame* guess_order_table = NULL;
  cpl_frame* guess_wavesol = NULL;
  const char* filename=NULL;
  cpl_frame* MODEL_CONF_OPT_frame=NULL;

  int maxit=200;

  int scenario=3;

  char paramname[256];
  cpl_parameter * p =NULL;
  int pre_overscan_corr=0;
  cpl_frame * line_intmon = NULL ;
  double exptime=0;
  cpl_propertylist* plist=NULL;
  cpl_boolean mode_phys;
  int resid_name_sw=0;
  /**************************************************************************/
  /* DFS management */
  /**************************************************************************/
  check( xsh_begin( frameset, parameters, &instrument, &raws, &calib,
		    recipe_tags, recipe_tags_size,
		    RECIPE_ID, XSH_BINARY_VERSION,
		    xsh_predict_description_short ) ) ;
  check( xsh_instrument_set_mode( instrument, XSH_MODE_SLIT));
  /* check critical parameter values */
  xsh_recipe_params_check(parameters,instrument,RECIPE_ID);
  /**************************************************************************/
  /* Recipe frames */
  /**************************************************************************/
  mode_phys=xsh_mode_is_physmod(calib,instrument);
  check(bpmap=xsh_check_load_master_bpmap(calib,instrument,RECIPE_ID));
  check( arclines = xsh_find_arc_line_list( calib, instrument));
  check( spectralformat_frame = xsh_find_frame_with_tag( calib, 
    XSH_SPECTRAL_FORMAT, instrument));

  /* Could be in sof */
  if (!mode_phys) {
    theo_tab_sing = xsh_find_frame_with_tag( calib, XSH_THEO_TAB_SING,
					     instrument);
    wave_tab_guess_frame = xsh_find_frame_with_tag( calib, XSH_WAVE_TAB_GUESS,
						    instrument);
    order_tab_recov_frame = xsh_find_frame_with_tag( calib, XSH_ORDER_TAB_RECOV,
						     instrument);
    solution_type = XSH_DETECT_ARCLINES_TYPE_POLY;
  } else {
    if( NULL == (model_config_frame = xsh_find_frame_with_tag( calib, 
							       XSH_MOD_CFG_TAB,
							       instrument))){


      model_config_frame=xsh_find_frame_with_tag( calib, XSH_MOD_CFG_OPT_REC,
                                                  instrument);
    }
    solution_type = XSH_DETECT_ARCLINES_TYPE_MODEL;
  }

  /* In UVB and VIS mode */
  if ( xsh_instrument_get_arm(instrument) != XSH_ARM_NIR){
    /* RAWS frameset must have only one file */
     XSH_ASSURE_NOT_ILLEGAL_MSG(cpl_frameset_get_size(raws) == 1,
                                "Provide one formatcheck frame for UVB,VIS arm");
    if((master_bias = xsh_find_frame_with_tag(calib,XSH_MASTER_BIAS,
					      instrument)) == NULL) {

      xsh_msg_warning("Frame %s not provided",XSH_MASTER_BIAS);
      xsh_error_reset();
    }

    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();
    }
  }
  /* IN NIR mode */
  else {
    /* RAWS frameset must have only two files */
    check(xsh_dfs_split_nir(raws,&on,&off));
    XSH_ASSURE_NOT_ILLEGAL_MSG(cpl_frameset_get_size(on) == 1,
                               "Provide one formatcheck on frame for NIR arm");
    XSH_ASSURE_NOT_ILLEGAL_MSG(cpl_frameset_get_size(off) == 1,
                               "Provide one formatcheck off frame for NIR arm");  
  }
  check( xsh_instrument_update_from_spectralformat( instrument,
    spectralformat_frame));


  if((line_intmon = xsh_find_frame_with_tag( calib, XSH_ARC_LINE_LIST_INTMON, 
                                             instrument)) == NULL) {
    xsh_error_reset();
  }
  /**************************************************************************/
  /* Recipe parameters */
  /**************************************************************************/
  check(detect_arclines_clipping = 
    xsh_parameters_clipping_detect_arclines_get(RECIPE_ID, parameters));
  check(detect_arclines_p = xsh_parameters_detect_arclines_get(RECIPE_ID,
    parameters));
  check( pre_overscan_corr = xsh_parameters_get_int( parameters, RECIPE_ID,
						     "pre-overscan-corr"));

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

  /* In UVB and VIS mode */
  if ( xsh_instrument_get_arm(instrument) != XSH_ARM_NIR){
    cpl_frame* fmtchk = NULL;

    /* prepare RAW frames in XSH format */
    check(xsh_prepare( raws, bpmap, master_bias, XSH_FMTCHK, instrument,
		       pre_overscan_corr,CPL_TRUE));
    check(fmtchk = cpl_frameset_get_frame(raws,0));

    if(master_bias != NULL) {
      /* subtract bias */
      check(predict_rmbias = xsh_subtract_bias(fmtchk,master_bias, 
						instrument,"FMTCHK_",
						pre_overscan_corr,0));
    } else {
      predict_rmbias =cpl_frame_duplicate(fmtchk);
    }

    if(master_dark != NULL) {
    /* subtract dark */
    filename = xsh_stringcat_any( "FMTCHK_DARK_",
			     xsh_instrument_arm_tostring( instrument ),
					   ".fits", (void*)NULL ) ;


    check(predict_rmdark = xsh_subtract_dark(predict_rmbias, master_dark,
					     filename, instrument));
    } else {
      predict_rmdark =cpl_frame_duplicate(predict_rmbias);
    }

  }
  /* in NIR mode */
  else{
    /* prepare ON frames in XSH format */
    check(xsh_prepare(on,bpmap, NULL, "ON", instrument,pre_overscan_corr,CPL_TRUE));
    /* prepare OFF frames in XSH format */
    check(xsh_prepare(off,bpmap, NULL, "OFF", instrument,pre_overscan_corr,CPL_TRUE));
 
    /* subtract dark */
    check(on_off = xsh_subtract_nir_on_off(on, off, instrument));
    check(predict_rmdark = cpl_frame_duplicate(
      cpl_frameset_get_frame(on_off,0)));
  }
  /* check on binning */
  if ( xsh_instrument_get_arm(instrument) != XSH_ARM_NIR){
     check(xsh_check_input_is_unbinned(predict_rmdark));
  }
  plist=cpl_propertylist_load(cpl_frame_get_filename(predict_rmdark),0);
  exptime=xsh_pfits_get_exptime(plist);
  xsh_free_propertylist(&plist);

  xsh_msg("Calling the xsh_detect_arclines");

  /* detect arclines */
  /* dan method */
  if(model_config_frame!=NULL) {
    resid_name_sw=1;
  } 
  check( xsh_detect_arclines_dan( predict_rmdark, theo_tab_sing,
			      arclines, wave_tab_guess_frame, 
                              order_tab_recov_frame,
			      model_config_frame, 
                              spectralformat_frame, 
                              &resid_tab_orders_frame,
			      &clean_arclines, &guess_wavesol,
			      &resid_dan, XSH_SOLUTION_RELATIVE,
			      detect_arclines_p, 
                              detect_arclines_clipping, 
				  instrument,RECIPE_ID,0,resid_name_sw));

/*
  xsh_free_frame(&clean_arclines);
  xsh_free_frame(&guess_wavesol);
  xsh_free_frame(&resid_tab_orders_frame);
*/
  
  /* 
  From residual table with all flag values extracts the one for which flag=0 
  */

  resid_map = cpl_frame_duplicate(resid_dan);
  cpl_table* resid = NULL;
  cpl_table* ext = NULL;
  const char* fname = NULL;
  char rtag[256];
  char fout[256];
  cpl_propertylist* phead = NULL;
  cpl_propertylist* xhead = NULL;

  fname = cpl_frame_get_filename(resid_dan);
  resid = cpl_table_load(fname, 1, 0);
  phead = cpl_propertylist_load(fname, 0);

  cpl_propertylist* qhead = NULL;
  qhead=cpl_propertylist_new();
  fname = cpl_frame_get_filename(clean_arclines);
  plist = cpl_propertylist_load(fname, 0);
  cpl_propertylist_copy_property_regexp(qhead, plist, "ESO QC*",0);
   cpl_propertylist_append(phead,qhead);
  xsh_free_propertylist(&qhead);

  sprintf(rtag, "FMTCHK_RESID_TAB_LINES_GFIT_%s",
      xsh_instrument_arm_tostring(instrument));
  sprintf(fout, "%s.fits", rtag);

  cpl_table_and_selected_int(resid, "Flag", CPL_EQUAL_TO, 0);
  ext = cpl_table_extract_selected(resid);
  cpl_table_save(ext, phead, xhead, fout, CPL_IO_DEFAULT);
  xsh_free_table(&resid);
  cpl_frame_set_filename(resid_map, fout);
  cpl_frame_set_tag(resid_map, rtag);
  if(model_config_frame != NULL) {
    xsh_add_temporary_file(fout);
  }
  xsh_free_propertylist(&phead);
  xsh_free_table(&ext);
/*
  check( xsh_detect_arclines( predict_rmdark, theo_tab_sing,
			      arclines, wave_tab_guess_frame, 
                              order_tab_recov_frame,
			      model_config_frame, 
                              spectralformat_frame, 
                              &resid_tab_orders_frame,
			      &clean_arclines, &guess_wavesol,
			      &resid_map, XSH_SOLUTION_RELATIVE,
			      detect_arclines_p, 
                              detect_arclines_clipping, 
                              instrument,RECIPE_ID,0,resid_name_sw));

  xsh_msg("file name=%s",cpl_frame_get_filename(resid_map));
*/


  double ann_fac=1.0;
  if ( model_config_frame != NULL){
    xsh_msg("Produce new config file");

    /*call the pipe_anneal function. The final 3 numeric parameters are:
      param3: the number of iterations, we keep it low here since we are
      just fine tuning an already good config.
      param4: A multiplier that is applied to all parameter ranges (only
      when param5!=0, see below), should be 1.0 here.

      param5: The scenario parameter, we are only interested in scenario
      3 (allows small ranges on all parameters except for dist coefficients)
      and 0 (uses parameters and ranges found in the input FITS config, the
      param4 multiplier is ignored) here.
      A switch can be set here to check if there is a cl option that specifies
      the use of input FITS config flags and ranges (param5=0) instead of the
      default scenarios (param5=3)*/


     sprintf(paramname,"xsh.%s.%s",RECIPE_ID, "model-maxit");
     check(p = cpl_parameterlist_find(parameters,paramname));
     check(maxit=cpl_parameter_get_int(p));

     sprintf(paramname,"xsh.%s.%s",RECIPE_ID, "model-anneal-factor");
     check(p = cpl_parameterlist_find(parameters,paramname));
     check(ann_fac=cpl_parameter_get_double(p));

     sprintf(paramname,"xsh.%s.%s",RECIPE_ID, "model-scenario");
     check(p = cpl_parameterlist_find(parameters,paramname));
     check(scenario=cpl_parameter_get_int(p));
     xsh_msg("maxit=%d ann_fac=%g scenario=%d",maxit,ann_fac,scenario);

     check(MODEL_CONF_OPT_frame=xsh_model_pipe_anneal( model_config_frame, resid_map,
                                                       maxit,ann_fac,scenario,1));

  }
  /*TODO: we need to generate the guess order table by the line table with flag=0 */
  check( guess_order_table=xsh_create_order_table(predict_rmdark,
						  spectralformat_frame,
						  resid_tab_orders_frame,
						  clean_arclines,
						  detect_arclines_p,
						  detect_arclines_clipping,
						  instrument));


  if(line_intmon) {
     check(xsh_wavecal_qclog_intmon(resid_map,line_intmon,exptime,instrument));
  }
  //check(xsh_table_merge_clean_and_resid_tabs(resid_map,clean_arclines));
  /**************************************************************************/
  /* Products */
  /**************************************************************************/
  xsh_msg("Saving products");
  /*
  check(xsh_add_product_table( clean_arclines, frameset,
                                 parameters, RECIPE_ID, instrument,NULL));
  */
  if ( guess_wavesol != NULL){
    check(xsh_add_product_table( guess_wavesol, frameset,
                                 parameters, RECIPE_ID, instrument,NULL));
  }
  if ( guess_order_table != NULL){
    check(xsh_add_product_table( guess_order_table, frameset, 
                                       parameters, RECIPE_ID, instrument,NULL));
  }
  if(model_config_frame == NULL) {
    check(xsh_wavetab_qc(resid_map,true));
  } else {
    check(xsh_wavetab_qc(resid_map,false));
  }


  if(model_config_frame!=NULL) {
    
    check(xsh_frame_table_resid_merge(resid_dan,resid_map,solution_type));
    /* as to anneal the mode we have corrected X one-pinhole positions to
     * match the 2dmap position of pinhole N 4, for consistency in the
     * comparisons with the actual image we need to put back the same correction
     */
    cpl_table* tab=NULL;
    cpl_propertylist* header=NULL;
    const char* name=cpl_frame_get_filename(resid_dan);
    tab=cpl_table_load(name,1,0);
    header=cpl_propertylist_load(name,0);
    if(xsh_instrument_get_arm(instrument) == XSH_ARM_NIR){
        cpl_table_add_scalar(tab,XSH_RESID_TAB_TABLE_COLNAME_XTHPRE,-0.125);
        cpl_table_add_scalar(tab,XSH_RESID_TAB_TABLE_COLNAME_XGAUSS,-0.125);
        cpl_table_add_scalar(tab,XSH_RESID_TAB_TABLE_COLNAME_XTHANNEAL,-0.125);
    } else if(xsh_instrument_get_arm(instrument) == XSH_ARM_UVB){
        cpl_table_add_scalar(tab,XSH_RESID_TAB_TABLE_COLNAME_XTHPRE,+0.51);
        cpl_table_add_scalar(tab,XSH_RESID_TAB_TABLE_COLNAME_XGAUSS,+0.51);
        cpl_table_add_scalar(tab,XSH_RESID_TAB_TABLE_COLNAME_XTHANNEAL,+0.51);
    }
    cpl_table_save(tab,header,NULL,name,CPL_IO_DEFAULT);
    xsh_free_propertylist(&header);
    xsh_free_table(&tab);
    check(xsh_add_product_table( resid_dan, frameset,parameters, RECIPE_ID, 
				 instrument,NULL));
    /*
   check(xsh_add_product_table( resid_map, frameset,parameters, RECIPE_ID, 
				 instrument,NULL));
    */
  } else {
    check(xsh_add_product_table( resid_map, frameset,parameters, RECIPE_ID, 
				 instrument,NULL));

  }

  sprintf(tag,"%s_ON",XSH_FMTCHK);
  if ( xsh_instrument_get_arm(instrument) != XSH_ARM_NIR){

    check(xsh_add_product_image(predict_rmbias,frameset,parameters,
                                RECIPE_ID,instrument,tag));

  } else {

    check(xsh_add_product_image(predict_rmdark,frameset,parameters,
                                RECIPE_ID,instrument,tag));
  }
  if ( model_config_frame != NULL){
    check(xsh_add_product_table(MODEL_CONF_OPT_frame,frameset,parameters, 
                                      RECIPE_ID, instrument,NULL));
  }

  xsh_msg("xsh_predict success !!");
 
  cleanup:
    xsh_end( RECIPE_ID, frameset, parameters );
    XSH_FREE(detect_arclines_clipping);
    XSH_FREE(detect_arclines_p);
    xsh_free_frameset(&raws);
    xsh_free_frameset(&calib);
    xsh_free_frameset(&on);
    xsh_free_frameset(&off);
    xsh_free_frameset(&on_off);
    xsh_free_frame(&guess_order_table);
    xsh_free_frame(&clean_arclines);
    xsh_free_frame(&resid_tab_orders_frame);
    xsh_free_frame(&resid_map);
    xsh_free_frame(&resid_dan);
    xsh_free_frame(&guess_wavesol);
    xsh_free_frame(&predict_rmbias);
    xsh_free_frame(&predict_rmdark); 
    xsh_free_frame(&MODEL_CONF_OPT_frame);
    xsh_free_frame(&bpmap);
    xsh_free_propertylist(&plist);
    //    xsh_pre_free( &pre);
    xsh_instrument_free(&instrument);
    return;
}

/**@}*/

