/* $Id: xsh_util_physmod.c,v 1.25 2012-12-18 14:12:51 amodigli Exp $
 *
 *   This file is part of the ESO X-shooter Pipeline                          
 *   Copyright (C) 2006 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 14:12:51 $
 * $Revision: 1.25 $
 * $Name: not supported by cvs2svn $
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/*---------------------------------------------------------------------------*/
/**
 * @defgroup xsh_model    xsh_model
 * @ingroup recipes
 *
 * This recipe is used to generate the physical model products. 
 * See man-page for details.
 */
/*---------------------------------------------------------------------------*/
/**@{*/
/*----------------------------------------------------------------------------
  Includes
  ---------------------------------------------------------------------------*/

#include <cpl.h>

#include "xsh_utils.h"
//#include "xsh_pfits.h"
#include "xsh_dfs.h"
#include "xsh_drl.h"
#include "xsh_pfits.h"
#include <xsh_model_kernel.h>
#include <xsh_model_utils.h>
#include <xsh_error.h>
#include <xsh_model_io.h>
#include <xsh_parameters.h>

#define RECIPE_ID "xsh_util_physmod"
#define RECIPE_AUTHOR "A.Modigliani, P. Bristow"
#define RECIPE_CONTACT "amodigli@eso.org"

/*-----------------------------------------------------------------------------
  Functions prototypes
  ---------------------------------------------------------------------------*/
static cpl_frame*
xsh_util_model_SPF_create(cpl_frame* config_frame,xsh_instrument* instrument);


static int xsh_util_physmod_create(cpl_plugin *);
static int xsh_util_physmod_exec(cpl_plugin *);
static int xsh_util_physmod_destroy(cpl_plugin *);
static int xsh_util_physmod(cpl_parameterlist *, cpl_frameset *);


/*-----------------------------------------------------------------------------
  Static variables
  ---------------------------------------------------------------------------*/

static char xsh_util_physmod_description[] =
  "This recipe generates the theoretical and the spectral format tables. \n"
  "and possibly the model based wave map.\n"
  "The sof file contains the names of the input FITS file\n"
  "tagged with XSH_MOD_CFG_TAB_arm.\n"
  "tagged with ARC_LINE_LIST_arm.\n"
  "This recipe has the following products:\n"
  "Model order traces for nine pinholes (PRO CATG = THEO_TAB_MULT_arm)\n"
  "Model order traces for nine pinholes (PRO CATG = THEO_TAB_IFU_arm)\n"
  "Model order traces for central pinhole (PRO CATG = THEO_TAB_SING_arm)\n"
  "Spectral format table (PRO CATG = SPECTRAL_FORMAT_TAB_arm)\n" 
  "Wave map image (PRO CATG = WAVE_MAP_arm)\n" 
  "Slit map image (PRO CATG = SLIT_MAP_arm)\n" ;

static char xsh_util_physmod_description_short[] ="Generate physical model products";

/*-----------------------------------------------------------------------------
  Functions code
  ---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/**
   @brief    Build the list of available plugins, for this module. 
   @param    list    the plugin list
   @return   0 iff everything is ok

   This function is exported.
*/
/*---------------------------------------------------------------------------*/
int cpl_plugin_get_info(cpl_pluginlist * list)
{
  cpl_recipe  *   recipe = cpl_calloc(1, sizeof(*recipe));
  cpl_plugin  *   plugin = &recipe->interface;

  cpl_plugin_init(plugin,
		  CPL_PLUGIN_API,
		  XSH_BINARY_VERSION,
		  CPL_PLUGIN_TYPE_RECIPE,
		  "xsh_util_physmod",
		  xsh_util_physmod_description_short,
		  xsh_util_physmod_description,
		  "Andrea Modigliani",
		  "amodigli@eso.org",
		  xsh_get_license(),
		  xsh_util_physmod_create,
		  xsh_util_physmod_exec,
		  xsh_util_physmod_destroy);

  cpl_pluginlist_append(list, plugin);
    
  return 0 ;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Setup the recipe options    
   @param    plugin  the plugin
   @return   0 iff everything is ok

   Create the recipe instance and make it available to the application 
   using the interface. 
*/
/*---------------------------------------------------------------------------*/
static int xsh_util_physmod_create(cpl_plugin * plugin)
{
  cpl_recipe      * recipe ;
  cpl_parameter* p=NULL;
 /* Reset library state */
  xsh_init();

  /* Get the recipe out of the plugin */
  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
    recipe = (cpl_recipe *)plugin ;
  else return -1 ;

  /* Create the parameters list in the cpl_recipe object */
  recipe->parameters = cpl_parameterlist_new() ;

  /* Set generic parameters (common to all recipes) */
  check( xsh_parameters_generic( RECIPE_ID, recipe->parameters ) ) ;
  xsh_parameters_decode_bp(RECIPE_ID,recipe->parameters,-1);
  p = cpl_parameter_new_value("xsh.xsh_model.binx",
			      CPL_TYPE_INT,
			      "X binning ",
			      "xsh.xsh_model", 1);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"binx");
  cpl_parameterlist_append(recipe->parameters,p);


  p = cpl_parameter_new_value("xsh.xsh_model.biny",
			      CPL_TYPE_INT,
			      "X binning ",
			      "xsh.xsh_model", 1);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"biny");
  cpl_parameterlist_append(recipe->parameters,p);


  p = cpl_parameter_new_value("xsh.xsh_model.spectral_format_tab",
			      CPL_TYPE_BOOL,
			      "Generate spectral format table  ",
			      "xsh.xsh_model", FALSE);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"spectral-format-tab");
  cpl_parameterlist_append(recipe->parameters,p);

  p = cpl_parameter_new_value("xsh.xsh_model.wavemap",
			      CPL_TYPE_BOOL,
			      "Generate slit and wave maps (time consuming) ",
			      "xsh.xsh_model", FALSE);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"wavemap");
  cpl_parameterlist_append(recipe->parameters,p);


 cleanup:

  return 0 ;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Execute the plugin instance given by the interface
   @param    plugin  the plugin
   @return   0 iff everything is ok
*/
/*---------------------------------------------------------------------------*/
static int xsh_util_physmod_exec(cpl_plugin * plugin)
{
  cpl_recipe  *   recipe ;

  /* Get the recipe out of the plugin */
  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
    recipe = (cpl_recipe *)plugin ;
  else return -1 ;

  return xsh_util_physmod(recipe->parameters, recipe->frames) ;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Destroy what has been created by the 'create' function
   @param    plugin  the plugin
   @return   0 iff everything is ok
*/
/*---------------------------------------------------------------------------*/
static int xsh_util_physmod_destroy(cpl_plugin * plugin)
{
  cpl_recipe  *   recipe ;

  /* Get the recipe out of the plugin */
  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
    recipe = (cpl_recipe *)plugin ;
  else return -1 ;

  cpl_parameterlist_delete(recipe->parameters) ;
  return 0 ;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    The FITS file creation occurs here 
   @param    parameters the list of parameters.
   @param    frameset   the frames list
   @return   0 iff everything is ok
   The recipe expects a text file and will create a FITS file out of it. 
*/
/*---------------------------------------------------------------------------*/
static int xsh_util_physmod(
			      cpl_parameterlist   *   parameters,
			      cpl_frameset        *   frameset)
{
 

  const char* recipe_tags[1] = {XSH_MOD_CFG};
  char wave_map_tag[256];
  char slit_map_tag[256];

  int recipe_tags_size = 1;

  cpl_frameset* raws=NULL;
  cpl_frameset* calib=NULL;
  cpl_frame*   wave_list=NULL ;
  cpl_frame*   xsh_config=NULL ;
  cpl_frame*   model_THE1_frm=NULL ;
  cpl_frame*   model_THE9_frm=NULL ;
  cpl_frame*   model_THE_IFU_frm=NULL ;

  cpl_frame*   spf_frm=NULL ;
  cpl_frame*   wavemap_frame=NULL ;
  cpl_frame*   slitmap_frame=NULL ;
  xsh_instrument* instrument=NULL;
  int gen_map=true;
  int gen_spf=true;
  cpl_parameter* p=NULL;
  int binx=0;
  int biny=0;
  char *prefix = NULL ;



  check( xsh_begin( frameset, parameters, &instrument, &raws, &calib,
		    recipe_tags, recipe_tags_size, RECIPE_ID,
                    XSH_BINARY_VERSION,
		    xsh_util_physmod_description_short ) ) ;
  check(xsh_config =  xsh_find_frame_with_tag( calib,XSH_MOD_CFG,
					       instrument));
  check(wave_list = xsh_find_frame_with_tag( calib, XSH_ARC_LINE_LIST,
					     instrument));

  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_model.binx"));
  check(binx = cpl_parameter_get_int(p));

  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_model.biny"));
  check(biny = cpl_parameter_get_int(p));


  xsh_instrument_set_binx(instrument,binx);
  xsh_instrument_set_biny(instrument,biny);

   check(model_THE9_frm=xsh_util_physmod_model_THE_create(xsh_config,
							  instrument,
							  wave_list,
                                                          binx,biny,9,0));

  check(xsh_add_product_table(model_THE9_frm,frameset,parameters, 
                                    RECIPE_ID,instrument,NULL));

  check(model_THE_IFU_frm=cpl_frame_duplicate(model_THE9_frm));
  xsh_free_frame(&model_THE9_frm);

  cpl_frame_set_tag(model_THE_IFU_frm,
                    XSH_GET_TAG_FROM_ARM(XSH_THEO_TAB_IFU,instrument));

  check(xsh_add_product_table(model_THE_IFU_frm,frameset,parameters, 
                                    RECIPE_ID,instrument,NULL));
  xsh_free_frame(&model_THE_IFU_frm);


  check(model_THE1_frm=xsh_util_physmod_model_THE_create(xsh_config,
							  instrument,
							  wave_list,
							 binx,biny,1,0));


  check(xsh_add_product_table(model_THE1_frm,frameset,parameters, 
                                    RECIPE_ID,instrument,NULL));
  xsh_free_frame(&model_THE1_frm);
  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_model.spectral_format_tab"));
  check(gen_spf = cpl_parameter_get_bool(p));

  if(gen_spf) {
  check(spf_frm=xsh_util_model_SPF_create(xsh_config,instrument));

  check(xsh_add_product_table(spf_frm, frameset, parameters, RECIPE_ID,
                                    instrument,NULL));

  }

  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_model.wavemap"));
  check(gen_map = cpl_parameter_get_bool(p));

  if(gen_map) {

    check(sprintf(wave_map_tag,"%s",
		  XSH_GET_TAG_FROM_ARM(XSH_WAVE_MAP,instrument)));

    check(sprintf(slit_map_tag,"%s",
		  XSH_GET_TAG_FROM_ARM(XSH_SLIT_MAP,instrument)));


    check( xsh_create_model_map( xsh_config, instrument,
                                 wave_map_tag, slit_map_tag,
                                 &wavemap_frame, &slitmap_frame,1));


    XSH_PREFIX(prefix,"WAVE_MAP",instrument);
    check(xsh_add_product_image( wavemap_frame, frameset,
				 parameters, RECIPE_ID, instrument, prefix ));

    XSH_PREFIX(prefix,"SLIT_MAP",instrument);
    check(xsh_add_product_image( slitmap_frame, frameset,
				 parameters, RECIPE_ID, instrument, prefix ));

  }

 cleanup:
  xsh_free_frame(&model_THE_IFU_frm);
  xsh_free_frame(&model_THE1_frm);
  xsh_free_frame(&model_THE9_frm);
  xsh_instrument_free(&instrument);
  xsh_free_frameset(&raws);
  xsh_free_frameset(&calib);
  XSH_FREE( prefix ) ;
  return 0 ;
}







/*--------------------------------------------------------------------------*/
/**
   @name xsh_util_model_SPF_create 
   @brief creates the model Spectral Format table corresponding to the best found model configuration
   @param  xsh_config_anneal frame of annealed model configuration parameters
   @param  xsh_instrument instrument instrument ARM setting

   @return output Spectral Format Table corresponding to model configuration

*/
/*--------------------------------------------------------------------------*/

static cpl_frame*
xsh_util_model_SPF_create(cpl_frame* config_frame,xsh_instrument* instrument)

{
  struct xs_3* p_xs_3_config=NULL;
  struct xs_3 xs_3_config;
  cpl_frame* spf_frame=NULL;
  char SPF_name[256];
  const char* pro_catg=NULL;
  //Load xsh model configuration
  p_xs_3_config=&xs_3_config;

  if (xsh_model_config_load_best(config_frame,p_xs_3_config)!=CPL_ERROR_NONE) {
    xsh_msg_error("Cannot load %s as a config", 
		  cpl_frame_get_filename(config_frame)) ;
    return NULL ;
  }


  check(pro_catg=XSH_GET_TAG_FROM_ARM(XSH_SPECTRAL_FORMAT,instrument));

  sprintf(SPF_name,"%s%s",pro_catg,".fits");

  check(spf_frame= xsh_model_spectralformat_create(p_xs_3_config,SPF_name));

  xsh_free_frame(&spf_frame);


  check(spf_frame=xsh_frame_product(SPF_name,pro_catg,
                                   CPL_FRAME_TYPE_TABLE,
                                   CPL_FRAME_GROUP_PRODUCT,
                                   CPL_FRAME_LEVEL_FINAL));


 cleanup:


  if(cpl_error_get_code() == CPL_ERROR_NONE) {
    return spf_frame;
  } else {
    xsh_print_rec_status(0);
    return NULL;
  }



}





/**@}*/
