/*                                                                            *
 *   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-10-02 15:47:47 $
 * $Revision: 1.133 $
 * $Name: not supported by cvs2svn $
 */

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

/*---------------------------------------------------------------------------*/
/**
 * @defgroup xsh_mbias    xsh_mbias
 * @ingroup recipes
 *
 * This recipe calculates the master bias frame
 * See man-page for details.
 */
/*---------------------------------------------------------------------------*/
/**@{*/

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


/* DRL steps */

/* Error handling */
#include <xsh_error.h>
/* Utility fonctions */
#include <xsh_utils.h>
#include <xsh_msg.h>
#include <xsh_data_instrument.h>
#include <math.h>
/* DFS functions */
#include <xsh_dfs.h>
/* DRL functions */
#include <xsh_drl.h>
#include <xsh_pfits.h>
#include <xsh_detmon.h>
#include <xsh_paf_save.h>
#include <xsh_utils_image.h>
#include <xsh_parameters.h>
#include <xsh_drl_check.h>
#include <xsh_model_arm_constants.h>

/* Library */
#include <cpl.h>
#include <assert.h>
/*----------------------------------------------------------------------------
                                Defines
 ----------------------------------------------------------------------------*/

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

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

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

static int xsh_mbias_create(cpl_plugin *);
static int xsh_mbias_exec(cpl_plugin *);
static int xsh_mbias_destroy(cpl_plugin *);

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

/*----------------------------------------------------------------------------
                            Static variables
 ----------------------------------------------------------------------------*/
static char xsh_mbias_description_short[] = "Create the master bias frame";

static char xsh_mbias_description[] =
    "This recipe creates a master bias frame by computing the median of all \
input bias frames.\n\
Input Frames : \n\
  - A set of n RAW frames (Format=RAW, n >=3, Tag = BIAS_arm)\n\
  - [OPTIONAL] A map of non linear bad pixels (Format=QUP, Tag = BP_MAP_NL_arm)\n\
  - [OPTIONAL] A map of reference bad pixels (Format = QUP,RAW, Tag = BP_MAP_RP_arm)\n\
Products : \n\
  - A master bias frame (Format=PRE, PRO.CATG = MASTER_BIAS_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_mbias_description_short,	/* Short help */
		    xsh_mbias_description,	/* Detailed help */
		    RECIPE_AUTHOR,	/* Author name */
		    RECIPE_CONTACT,	/* Contact address */
		    xsh_get_license(),	/* Copyright */
		    xsh_mbias_create, 
                    xsh_mbias_exec, 
                    xsh_mbias_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_mbias_create(cpl_plugin * plugin)
{
  cpl_recipe *recipe = NULL;
  xsh_fpn_param fpn_param = {10,10,1024,1024,10,100};
  xsh_ron_param ron_param = {"ALL",
                             10,100,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,25};
  xsh_struct_param struct_param = {-1,-1};
  xsh_stack_param stack_param = {"median",5.,5.};
  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_stack_create(RECIPE_ID,recipe->parameters,stack_param));
  check(xsh_parameters_fpn_create(RECIPE_ID,recipe->parameters,fpn_param));
  check(xsh_parameters_ron_create(RECIPE_ID,recipe->parameters,ron_param));
  check(xsh_parameters_struct_create(RECIPE_ID,recipe->parameters,struct_param));
  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_mbias_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_mbias(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_mbias_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;
    }
}




/*---------------------------------------------------------------------------*/
/**
  @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_mbias(cpl_parameterlist * parameters, cpl_frameset * frameset)
{
  const char* recipe_tags[1] = {XSH_BIAS};
  int recipe_tags_size = 1;

  cpl_frameset *raws = NULL;
  cpl_frameset *calib = NULL;
  cpl_frame *bpmap = NULL;
  cpl_frame *master_bias = NULL;
  cpl_frame *product = NULL;
  xsh_instrument* instrument  = NULL;

  cpl_frame* bias_frm=NULL;
  cpl_propertylist* plist=NULL;
  char name[256];
  const char* ftag;

  int pre_overscan_corr=0;
  xsh_stack_param* stack_par=NULL;

  /**************************************************************************/
  /* DFS management */
  /**************************************************************************/
  check( xsh_begin( frameset, parameters, &instrument, &raws, &calib,
                    recipe_tags, recipe_tags_size,
                    RECIPE_ID, XSH_BINARY_VERSION,
                    xsh_mbias_description_short ) ) ;

  /* check critical parameter values */
  xsh_recipe_params_check(parameters,instrument,RECIPE_ID);
  /**************************************************************************/
  /* Recipe frames */
  /**************************************************************************/
  //AModigliani: why should be prevent to reduce < 3 frames if it works?
  //XSH_ASSURE_NOT_ILLEGAL(cpl_frameset_get_size(raws) >= 3);
  check(bpmap=xsh_check_load_master_bpmap(calib,instrument,RECIPE_ID));


  check(bias_frm=cpl_frameset_get_frame(raws,0));
  check(plist=cpl_propertylist_load(cpl_frame_get_filename(bias_frm),0));
  xsh_free_propertylist(&plist);

  ftag=XSH_GET_TAG_FROM_ARM_EXT(XSH_MASTER_BIAS,instrument);
  sprintf(name,"%s.fits",ftag);
  xsh_msg("tag=%s",ftag);

  /**************************************************************************/
  /* Recipe parameters */
  /**************************************************************************/
 check( stack_par = xsh_stack_frames_get( RECIPE_ID, parameters));
  /**************************************************************************/
  /* Recipe code */
  /**************************************************************************/

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

  /* remove cosmic rays and merge the RAWS */
  
  if(strcmp(stack_par->stack_method,"mean") == 0) {
    check(master_bias = xsh_create_master_bias2(raws,stack_par,instrument,ftag,1));
  } else {
    check(master_bias = xsh_create_master_bias2(raws,stack_par,instrument,ftag,0));
  }


  /* create master bias */
  check(product=xsh_compute_qc_on_master_bias(raws,master_bias,instrument,parameters));

  /**************************************************************************/
  /* Products */
  /**************************************************************************/

  xsh_msg("Save products");
  //check( xsh_add_product_pre(product, frameset, parameters, RECIPE_ID,
  //  instrument));
  check(xsh_add_product_image(product, frameset, parameters,RECIPE_ID, instrument,XSH_MASTER_BIAS));

  xsh_msg("xsh_mbias success!!"); 

  cleanup:
    xsh_end( RECIPE_ID, frameset, parameters );

    xsh_free_propertylist(&plist);
    xsh_instrument_free(&instrument);
    xsh_free_frame(&product);
    xsh_free_frameset(&raws);
    xsh_free_frameset(&calib);
    xsh_free_frame(&master_bias);
    xsh_free_frame(&bpmap);

    cpl_free(stack_par);
    return;
}

/**@}*/


