/* $Id: xsh_lingain.c,v 1.51 2012-12-18 15:25:21 amodigli Exp $
 *
 * This file is part of the DETMON Pipeline
 * Copyright (C) 2002,2003 European Southern Observatory
 *
 * This program 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 * $Author: amodigli $
 * $Date: 2012-12-18 15:25:21 $
 * $Revision: 1.51 $
 * $Name: not supported by cvs2svn $
 */

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

/*----------------------------------------------------------------------------
  Includes and Defines
  ----------------------------------------------------------------------------*/
#include <cpl.h>
#include "xsh_detmon.h"
#include "xsh_detmon_lg.h"

//#include "uves_plugin.h"
//#include "uves_chip_type.h"
#include "xsh_dfs.h"
#include "xsh_drl.h"
#include "xsh_msg.h"
#include "xsh_error.h"
#include "xsh_utils.h"
#include <xsh_data_instrument.h>
#include "xsh_parameters.h"
#include "xsh_badpixelmap.h"

/* Define here the DO.CATG keywords */

#define XSH_LINGAIN_ON_RAW(it) ((it) == 0 ? XSH_LINEARITY_UVB_ON :     	\
                                (it) == 1 ? XSH_LINEARITY_VIS_ON :     	\
                                (it) == 2 ? XSH_LINEARITY_NIR_ON :	\
                                "???")

#define XSH_LINGAIN_OFF_RAW(it) ((it) == 0 ? XSH_LINEARITY_UVB_OFF :   	\
                                 (it) == 1 ? XSH_LINEARITY_VIS_OFF :   	\
                                 (it) == 2 ? XSH_LINEARITY_NIR_OFF :	\
				 "???")

#define XSH_LINGAIN_DET_LIN_INFO(it) ((it) == 0 ? XSH_DET_LIN_INFO_UVB : \
                                      (it) == 1 ? XSH_DET_LIN_INFO_VIS : \
                                      (it) == 2 ? XSH_DET_LIN_INFO_NIR : \
				      "???")

#define XSH_LINGAIN_GAIN_INFO(it) ((it) == 0 ? XSH_GAIN_INFO_UVB :	\
                                   (it) == 1 ? XSH_GAIN_INFO_VIS :	\
                                   (it) == 2 ? XSH_GAIN_INFO_NIR :	\
                                   "???")

#define XSH_LINGAIN_COEFFS_CUBE(it) ((it) == 0 ? XSH_COEFFS_CUBE_UVB :	\
                                     (it) == 1 ? XSH_COEFFS_CUBE_VIS :	\
                                     (it) == 2 ? XSH_COEFFS_CUBE_NIR :	\
                                     "???")

#define XSH_LINGAIN_BP_MAP_NL(it) ((it) == 0 ? XSH_BP_MAP_NL_UVB :	\
                                   (it) == 1 ? XSH_BP_MAP_NL_VIS :	\
                                   (it) == 2 ? XSH_BP_MAP_NL_NIR :	\
                                   "???")

#define XSH_LINGAIN_RAW_BP_MAP_NL(it) ((it) == 0 ? XSH_RAW_BP_MAP_NL_UVB :  \
                                   (it) == 1 ? XSH_RAW_BP_MAP_NL_VIS :	\
                                   (it) == 2 ? XSH_RAW_BP_MAP_NL_NIR :	\
                                   "???")

#define XSH_LINGAIN_AUTOCORR(it) ((it) == 0 ? XSH_AUTOCORR_UVB :	\
                                  (it) == 1 ? XSH_AUTOCORR_VIS :	\
                                  (it) == 2 ? XSH_AUTOCORR_NIR :	\
                                  "???")

#define XSH_LINGAIN_DIFF_FLAT(it) ((it) == 0 ? XSH_DIFF_FLAT_UVB :	\
                                   (it) == 1 ? XSH_DIFF_FLAT_VIS :	\
                                   (it) == 2 ? XSH_DIFF_FLAT_NIR :	\
                                   "???")

#define RECIPE_ID "xsh_lingain"
#define RECIPE_AUTHOR "Lander de Bilbao,A.Modigliani"
#define RECIPE_CONTACT "amodigli@eso.org"

/* Copy here instrument specific keywords which need to be in the PAF file */
#define INSTREGEXP   "ESO INS SETUP ID"

#define PAFREGEXP    "^(" REGEXP "|" INSTREGEXP ")$"
#define NIR TRUE
#define OPT FALSE
#define XSH_PIX2PIX CPL_TRUE
#define XSH_EXTS_RED -1
#define XSH_BPMBIN 1
#define XSH_TOL 0.1
/*----------------------------------------------------------------------------
  Functions prototypes
  ----------------------------------------------------------------------------*/
static int xsh_lingain_create(cpl_plugin *);
static int xsh_lingain_exec(cpl_plugin *);
static int xsh_lingain_destroy(cpl_plugin *);
static int 
xsh_lingain(cpl_frameset            * frameset,
	    cpl_parameterlist * parlist);

cpl_error_code
xsh_lingain_fill_parlist_default_opt(cpl_parameterlist * parlist);
cpl_error_code
xsh_lingain_fill_parlist_default_nir(cpl_parameterlist * parlist);
static cpl_error_code
xsh_lingain_set_saturation_limit(cpl_parameterlist * parlist,
				 xsh_instrument* instrument );

/* AMO: not used.
static cpl_error_code
xsh_lingain_pre_format(const cpl_frameset* raws, 
                       xsh_instrument* instrument, 
                       cpl_frame* bpmap,
                       const int arm_id,
                       cpl_frameset** frameset);
*/
/*----------------------------------------------------------------------------
  Static variables
  ----------------------------------------------------------------------------*/
static char xsh_lingain_description_short[] = "Computes detector's gain/linearity-map";

static char xsh_lingain_description[] =
  "This recipe computes detector linearity coefficients and gain\n\
Input Frames : \n\
  arm = UVB-VIS: \n\
  - A set of n RAW linearity frames (Format=RAW, n >=8, Tag = LINEARITY_arm_ON)\n\
  - A set of n RAW bias frames (Format=RAW, n >=1, Tag = LINEARITY_arm_OFF)\n\
  arm = NIR:\n\
  - A set of n RAW linearity on frames (Format=RAW, n >=8, Tag = LINEARITY_arm_ON)\n\
  - A set of n RAW linearity off frames (Format=RAW, n >=8, Tag = LINEARITY_arm_OFF)\n\
  - [OPTIONAL] a static bad pixel map (PRO.CATG=BP_MAP_RP_arm) \n\
  Note: on and off frames are taken in pairs sequence: OFF-ON-ON-OFF, \n\
  at least 16 frames.\n\
Products : \n\
  - A linearity map table, PRO.CATG = BP_MAP_LIN_NIR\n\
  - A gain table, PRO.CATG = GAIN_INFO\n\
  - A cube cointaining the linearity coefficients, PRO.CATG = COEFFS_CUBE_arm\n\
  - A linearity map image (RAW format), PRO.CATG = RAW_BP_MAP_NL_arm\n\
  - A linearity map image (PRE format), PRO.CATG = BP_MAP_NL_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_lingain_description_short,	/* Short help */
		  xsh_lingain_description,	/* Detailed help */
		  RECIPE_AUTHOR,	/* Author name */
		  RECIPE_CONTACT,	/* Contact address */
		  xsh_get_license(),	/* Copyright */
		  xsh_lingain_create, 
		  xsh_lingain_exec, 
		  xsh_lingain_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_lingain_create(cpl_plugin * plugin)
{
  cpl_recipe *recipe = NULL;
  /* 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_lingain_fill_parlist_default_opt(recipe->parameters));

 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_lingain_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_lingain(recipe->frames,recipe->parameters);

 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_lingain_destroy(cpl_plugin * plugin)
{
  cpl_recipe *recipe = NULL;

  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_set_defaults(cpl_parameterlist* pars,
                        xsh_instrument* inst)
{
   cpl_parameter* p=NULL;

  if (xsh_instrument_get_arm(inst) == XSH_ARM_UVB){

      p=cpl_parameterlist_find(pars, "xshoo.xsh_lingain.kappa");

     if(xsh_parameter_get_default_flag(p) == 0) {
     //if( fabs(val-def) > DBL_MIN ) {
        /* if the user has not set the parameter use default */
        cpl_parameter_set_double(p,5.);
     }    
  }

 //cleanup:
 
  return cpl_error_get_code();

}

/*---------------------------------------------------------------------------*/
/*
  @brief    Interpret the command line options and execute the data processing
  @param    frameset    the frames list
  @param    parlist     the parameters list
  @return   0 if everything is ok
*/
/*---------------------------------------------------------------------------*/

static int 
xsh_lingain(cpl_frameset            * frameset,
	    cpl_parameterlist * parlist)
{

   const char* recipe_tags[6] = {XSH_LINEARITY_UVB_ON,XSH_LINEARITY_UVB_OFF,
                                 XSH_LINEARITY_VIS_ON,XSH_LINEARITY_VIS_OFF,
                                 XSH_LINEARITY_NIR_ON,XSH_LINEARITY_NIR_OFF};
  int recipe_tags_size = 6;

  cpl_error_code error=0;
  int processed=0;
  cpl_parameterlist* plist=NULL;
  xsh_instrument* instrument=NULL;
  cpl_frameset* raws=NULL;
  cpl_frameset* calib=NULL;
  cpl_frameset* pros=NULL;

  cpl_propertylist * lintbl = NULL;
  cpl_propertylist * gaintbl = NULL;
  cpl_propertylist * coeffscube = NULL;
  cpl_propertylist * bpm = NULL;
  cpl_propertylist * corr = NULL;
  cpl_propertylist * diff_flat =NULL; 
  cpl_frame* bpmap_nl=NULL;
  cpl_image* ima=NULL;
  char name[256];
  cpl_propertylist* head=NULL;
  cpl_frame *bpmap = NULL;
  cpl_frame* coadd_bp_map=NULL;
  cpl_image* crox=NULL;


  char* bp_nl_tag=NULL;
  char* bp_nl_name=NULL;
  xsh_pre* pre_bp_nl = NULL;
  cpl_frame* bp_nl_frame = NULL;


  /**************************************************************************/
  /* DFS management */
  /**************************************************************************/
  check( xsh_begin( frameset, parlist, &instrument, &raws, &calib,
		    recipe_tags, recipe_tags_size,
		    RECIPE_ID, XSH_BINARY_VERSION,
		    xsh_lingain_description_short ) ) ;
  if((bpmap=xsh_find_frame_with_tag(calib,XSH_BP_MAP_RP,instrument))==NULL) {
    xsh_msg("%s not provided",XSH_BP_MAP_RP);
  }
  check(plist=xsh_parameterlist_duplicate(parlist));

  if ( xsh_instrument_get_arm(instrument) == XSH_ARM_NIR){

    //xsh_lingain_pre_format(raws,instrument,bpmap,2,&frameset);
      
    xsh_lingain_fill_parlist_default_nir(plist);
    xsh_lingain_set_saturation_limit(plist,instrument);

    processed++;

    lintbl=xsh_detmon_fill_prolist("DET_LIN_INFO_NIR","TYPE","TECH",CPL_FALSE);

    gaintbl=xsh_detmon_fill_prolist("GAIN_INFO_NIR","TYPE","TECH",CPL_FALSE);

    coeffscube=xsh_detmon_fill_prolist("COEFFS_CUBE_NIR","TYPE","TECH",CPL_FALSE);

    bpm=xsh_detmon_fill_prolist("RAW_BP_MAP_NL_NIR","TYPE","TECH",CPL_FALSE);

    corr=xsh_detmon_fill_prolist("AUTOCORR_NIR","TYPE","TECH",CPL_FALSE);

    diff_flat=xsh_detmon_fill_prolist("DIFF_FLAT_NIR","TYPE","TECH",CPL_FALSE);

    check(error = xsh_detmon_lg(raws,
				plist,
				XSH_LINEARITY_NIR_ON,
				XSH_LINEARITY_NIR_OFF,
				RECIPE_ID,
				"xshoo",
				PAFREGEXP,
				lintbl,
				gaintbl,
				coeffscube, 
				bpm,
				corr, 
				diff_flat,
				PACKAGE "/" PACKAGE_VERSION,
				NULL, NULL, NIR));

  } else  if ( xsh_instrument_get_arm(instrument) == XSH_ARM_UVB){

    //xsh_lingain_pre_format(raws,instrument,bpmap,0,&frameset);

    check(xsh_lingain_fill_parlist_default_opt(plist));
    check(xsh_params_set_defaults(parlist,instrument));
    xsh_lingain_set_saturation_limit(plist,instrument);

    processed++;

    lintbl=xsh_detmon_fill_prolist("DET_LIN_INFO_UVB","TYPE","TECH",CPL_FALSE);

    gaintbl=xsh_detmon_fill_prolist("GAIN_INFO_UVB","TYPE","TECH",CPL_FALSE);

    coeffscube=xsh_detmon_fill_prolist("COEFFS_CUBE_UVB","TYPE","TECH",CPL_FALSE);

    bpm=xsh_detmon_fill_prolist("RAW_BP_MAP_NL_UVB","TYPE","TECH",CPL_FALSE);

    corr=xsh_detmon_fill_prolist("AUTOCORR_UVB","TYPE","TECH",CPL_FALSE);

    diff_flat=xsh_detmon_fill_prolist("DIFF_FLAT_UVB","TYPE","TECH",CPL_FALSE);
    check(error = xsh_detmon_lg(raws,
				plist,
				XSH_LINEARITY_UVB_ON,
				XSH_LINEARITY_UVB_OFF,
				RECIPE_ID,
				"xshoo",
				PAFREGEXP,
				lintbl,
				gaintbl,
				coeffscube, 
				bpm,
				corr, 
				diff_flat,
				PACKAGE "/" PACKAGE_VERSION,
				NULL, NULL, OPT));



  } else  if ( xsh_instrument_get_arm(instrument) == XSH_ARM_VIS) {

    //xsh_lingain_pre_format(raws,instrument,bpmap,1,&frameset);

    xsh_lingain_fill_parlist_default_opt(plist);

    xsh_lingain_set_saturation_limit(plist,instrument);

    processed++;

    lintbl=xsh_detmon_fill_prolist("DET_LIN_INFO_VIS","TYPE","TECH",CPL_FALSE);

    gaintbl=xsh_detmon_fill_prolist("GAIN_INFO_VIS","TYPE","TECH",CPL_FALSE);

    coeffscube=xsh_detmon_fill_prolist("COEFFS_CUBE_VIS","TYPE","TECH",CPL_FALSE);

    bpm=xsh_detmon_fill_prolist("RAW_BP_MAP_NL_VIS","TYPE","TECH",CPL_FALSE);

    corr=xsh_detmon_fill_prolist("AUTOCORR_VIS","TYPE","TECH",CPL_FALSE);

    diff_flat=xsh_detmon_fill_prolist("DIFF_FLAT_VIS","TYPE","TECH",CPL_FALSE);

    check(error = xsh_detmon_lg(raws,
				plist,
				XSH_LINEARITY_VIS_ON,
				XSH_LINEARITY_VIS_OFF,
				RECIPE_ID,
				"xshoo",
				PAFREGEXP,
				lintbl,
				gaintbl,
				coeffscube, 
				bpm,
				corr, 
				diff_flat,
				PACKAGE "/" PACKAGE_VERSION,
				NULL, NULL, OPT));



  }
  
  pros=cpl_frameset_new();
  check(xsh_dfs_extract_pro_frames(raws,pros));
  check(xsh_frameset_merge(frameset,pros));
  xsh_free_frameset(&pros);
  check(bpmap_nl=xsh_find_frame_with_tag(frameset,XSH_RAW_BP_MAP_NL,instrument));

  /* special put in PRE format */
  check( pre_bp_nl = xsh_pre_create(bpmap_nl , NULL, NULL, instrument,0,CPL_FALSE));
  bp_nl_tag=cpl_sprintf("%s_%s",XSH_BP_MAP_NL,
		  xsh_instrument_arm_tostring( instrument ));
  bp_nl_name=cpl_sprintf("%s.fits",bp_nl_tag);
  check( bp_nl_frame = xsh_pre_save( pre_bp_nl, bp_nl_name,bp_nl_tag,1 ));
  cpl_frameset_insert(frameset, bp_nl_frame);


  check(sprintf(name,cpl_frame_get_filename(bp_nl_frame)));
  check(ima=cpl_image_load(name,CPL_TYPE_FLOAT,0,0));
  check(head=cpl_propertylist_load(name,0));
  cpl_propertylist_erase_regexp(head, "NPIXSAT",0);
  cpl_propertylist_erase_regexp(head, "FPIXSAT",0);
  check(xsh_bpmap_bitwise_to_flag(ima,QFLAG_NON_LINEAR_PIXEL));
  /* Flag NIR bad pixels with a crox */
  if ( xsh_instrument_get_arm(instrument) == XSH_ARM_NIR) {
     check(crox=xsh_image_flag_bptype_with_crox(ima));
     check(cpl_image_save(crox,name,CPL_BPP_IEEE_FLOAT,head,CPL_IO_DEFAULT));
     xsh_free_image(&crox);
  } else {
     check(cpl_image_save(ima,name,CPL_BPP_IEEE_FLOAT,head,CPL_IO_DEFAULT));
  }
  xsh_free_image(&ima);
  xsh_free_propertylist(&head);

/* Reflex analisis decided to remove generation of MASTER_BP_MAP_ARM 
  if(bpmap!=NULL) {
     xsh_msg( "Master bp map is bit-wise OR combination of input with non-linear pixels" ) ;
     check(coadd_bp_map=cpl_frame_duplicate(bpmap));
     sprintf(name,cpl_frame_get_filename(bpmap));
  } else {
     xsh_msg( "Master bp map is given by non-linear pixels" ) ;
     check(coadd_bp_map=cpl_frame_duplicate(bp_nl_frame));
     sprintf(name,cpl_frame_get_filename(bp_nl_frame));
  }
  check(ima=cpl_image_load(name,CPL_TYPE_FLOAT,0,0));
  check(head=cpl_propertylist_load(name,0));
  check(pro_catg=XSH_GET_TAG_FROM_ARM(XSH_MASTER_BP_MAP_NLIN,instrument));
  sprintf(name,"%s.fits",pro_catg);
  check(cpl_image_save(ima,name,CPL_BPP_IEEE_FLOAT,head,CPL_IO_DEFAULT));
  xsh_free_image(&ima);
  xsh_free_propertylist(&head);


  if(bpmap!=NULL) {
     check(xsh_badpixelmap_coadd(coadd_bp_map,bp_nl_frame));
  }
  check(cpl_frame_set_tag(coadd_bp_map,pro_catg));
  check( xsh_add_product_bpmap(coadd_bp_map, frameset, parlist,
                               RECIPE_ID, instrument, NULL ));

  xsh_free_frame(&coadd_bp_map);
*/


  if(processed>0) {
    /* Propagate the error, if any */
    cpl_ensure_code(!error, error);
  } else {
    xsh_msg("No data has been processed.");
    xsh_msg("Pls check if input frame set contains valid tags");
  }


 cleanup:

    xsh_free_frame(&coadd_bp_map);
    xsh_free_frameset(&pros);
    xsh_free_image(&ima);
    xsh_free_propertylist(&head);
    xsh_free_propertylist(&lintbl);
    xsh_free_propertylist(&gaintbl);
    xsh_free_propertylist(&coeffscube);
    xsh_free_propertylist(&bpm);
    xsh_free_propertylist(&corr);
    xsh_free_propertylist(&diff_flat);
    xsh_pre_free(&pre_bp_nl);
  return CPL_ERROR_NONE;
}

/* AMO not used
static cpl_error_code
xsh_lingain_pre_format(const cpl_frameset* raws, 
                       xsh_instrument* instrument, 
                       cpl_frame* bpmap,
                       const int arm_id,
                       cpl_frameset** frameset)
{

  cpl_frameset* lin_pre_set=NULL;
  cpl_frameset* bias_pre_set=NULL;
  cpl_frameset* bias_set=NULL;
  cpl_frameset* lin_set=NULL;

  cpl_frame* frm=NULL;
  int pre_overscan_corr=0;


  int i=0;
  int n=0;


  check(bias_set=xsh_frameset_extract(*frameset,XSH_LINGAIN_OFF_RAW(arm_id)));
  check(lin_set=xsh_frameset_extract(raws,XSH_LINGAIN_ON_RAW(arm_id)));

  check(xsh_prepare(lin_set, bpmap, NULL, XSH_LINEARITY,  instrument,pre_overscan_corr,CPL_TRUE));
  check(lin_pre_set=xsh_frameset_extract_pre(lin_set,XSH_LINEARITY));
  xsh_free_frameset(&lin_set);

  check(xsh_prepare(bias_set, bpmap, NULL, XSH_BIAS, instrument,pre_overscan_corr,CPL_TRUE));
  check(bias_pre_set=xsh_frameset_extract_pre(bias_set,XSH_BIAS));
  xsh_free_frameset(&bias_set);

  check(n=cpl_frameset_get_size(bias_pre_set));
  xsh_free_frameset(frameset);
  *frameset=cpl_frameset_new();
  for(i=0;i<n;i++) {
     check(frm=cpl_frameset_get_frame(bias_pre_set,i));
     check(cpl_frameset_insert(*frameset,cpl_frame_duplicate(frm)));
  }

  check(n=cpl_frameset_get_size(lin_pre_set));
  for(i=0;i<n;i++) {
     check(frm=cpl_frameset_get_frame(lin_pre_set,i));
     check(cpl_frameset_insert(*frameset,cpl_frame_duplicate(frm)));
  }

  cleanup:

  xsh_free_frameset(&bias_set);
  xsh_free_frameset(&lin_set);

  xsh_free_frameset(&bias_pre_set);
  xsh_free_frameset(&lin_pre_set);

  return cpl_error_get_code();

}
*/

cpl_error_code
xsh_lingain_fill_parlist_default_opt(cpl_parameterlist * parlist)
{

  cpl_error_code error =
    xsh_detmon_lg_fill_parlist_opt_default(parlist, RECIPE_ID, PACKAGE);
  cpl_parameter * p;

  cpl_ensure_code(!error, error);

  /* FIXME: Put the parameter names and their new default values in two arrays
     and iterate through them */
  p = cpl_parameterlist_find(parlist, PACKAGE "." RECIPE_ID ".pix2pix");

  cpl_ensure_code(p != NULL, CPL_ERROR_DATA_NOT_FOUND);

  error = cpl_parameter_set_default_bool(p, XSH_PIX2PIX);

  p = cpl_parameterlist_find(parlist, PACKAGE "." RECIPE_ID ".tolerance");

  cpl_ensure_code(p != NULL, CPL_ERROR_DATA_NOT_FOUND);

  error = cpl_parameter_set_default_double(p, XSH_TOL);

  cpl_ensure_code(!error, error);

  return CPL_ERROR_NONE;
}


cpl_error_code
xsh_lingain_fill_parlist_default_nir(cpl_parameterlist * parlist)
{



  cpl_error_code error =
    xsh_detmon_lg_fill_parlist_nir_default(parlist,RECIPE_ID,
					   PACKAGE_TARNAME);
  cpl_parameter * p;

  cpl_ensure_code(!error, error);


  p = cpl_parameterlist_find(parlist, PACKAGE_TARNAME "." RECIPE_ID ".bpmbin");

  cpl_ensure_code(p != NULL, CPL_ERROR_DATA_NOT_FOUND);

  error = cpl_parameter_set_default_bool(p, XSH_BPMBIN);

  cpl_ensure_code(!error, error);


  return CPL_ERROR_NONE;

}



static cpl_error_code
xsh_lingain_set_saturation_limit(cpl_parameterlist * parlist,
				 xsh_instrument* instrument )
{

  cpl_error_code error =0;
  cpl_parameter * p;
  double val=0;
  double thresh_max=65000; /* UVB/VIS */

  if ( xsh_instrument_get_arm(instrument) == XSH_ARM_NIR) {
    thresh_max=42000;
   }

  cpl_ensure_code(!error, error);

  p = cpl_parameterlist_find(parlist, PACKAGE "." RECIPE_ID ".saturation_limit");

  cpl_ensure_code(p != NULL, CPL_ERROR_DATA_NOT_FOUND);
  val=cpl_parameter_get_double(p);

  if( fabs(val+1.) < 0.00001) {  
    error = cpl_parameter_set_default_double(p, thresh_max);
  }
  cpl_ensure_code(!error, error);

  return CPL_ERROR_NONE;

}

