/* $Id: xsh_model_utils.c,v 1.13 2012-12-18 14:15:45 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:15:45 $
 * $Revision: 1.13 $
 * $Name: not supported by cvs2svn $
 */

#include <xsh_model_utils.h>
#include <xsh_model_kernel.h>
#include <xsh_model_io.h>
#include <xsh_pfits.h>
#include <xsh_dfs.h>
#include <xsh_utils.h>
#include <xsh_msg.h>
#include <xsh_error.h>
#include <xsh_data_instrument.h>
/*--------------------------------------------------------------------------*/
/**
   @name xsh_startup_model_THE_create 
   @brief creates the model THE 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
   @param  wave_list input frame wavelength list 
   @param  binx  x bin value
   @param  biny  y bin value
   @param  num_ph number of pinholes
   @param  sky    switch to change tag and filename:0 THEO_TAB*, 1:SKY_TAB

   @return model_THE_frm output model THE table corresponding to line list and 
   annealed model configuration or NULL if failure

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


cpl_frame*
xsh_util_physmod_model_THE_create(cpl_frame* config_frame,
				    xsh_instrument* instrument,
				    cpl_frame* wave_list,
				    const int binx, const int biny,
                                  const int num_ph, const int sky)

{


  struct xs_3* p_xs_3_config=NULL;
  struct xs_3 xs_3_config; 
  const char* line_list=NULL;
  cpl_frame* THE_frm=NULL;

  char THE_filename[256];
 
  const char* pro_catg=NULL;
  cpl_propertylist* plist=NULL;
  cpl_table* tab=NULL;
  const char* seq_arm=NULL;
  int i=0;
  int* pslit_index=NULL;
  //xsh_pre * pre_sci = 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 ;
  }
      /*Update prism temperature(s) before call to phys mod so that predicted
	positions are for sci exposure prism temperature(s)*/
/*   if ( sci_frame != NULL) { */
/*     check( pre_sci = xsh_pre_load (sci_frame, instrument)); */
/*     if (xsh_instrument_get_arm(instrument)==XSH_ARM_VIS) { */
/*       p_xs_3_config->temper=xsh_pfits_get_temp5(pre_sci->data_header); */
/*     } */
/*     else if (xsh_instrument_get_arm(instrument)==XSH_ARM_UVB) { */
/*       p_xs_3_config->temper=xsh_pfits_get_temp2(pre_sci->data_header); */
/*     } */
/*     else if (xsh_instrument_get_arm(instrument)==XSH_ARM_NIR) { */
/*       p_xs_3_config->temper=xsh_pfits_get_temp82(pre_sci->data_header); */
/*       p_xs_3_config->t_ir_p2=xsh_pfits_get_temp82(pre_sci->data_header); */
/*       p_xs_3_config->t_ir_p3=xsh_pfits_get_temp82(pre_sci->data_header); */
/*     } */
/*   } */
/*   else { */
/*     xsh_msg("Using physical model CFG file prism temperature, no update to sci exposure prism temperature available"); */
/*   } */

  check(line_list=cpl_frame_get_filename(wave_list));

  check(xsh_model_binxy(p_xs_3_config,binx,biny));

  if(num_ph == 1) {
     if(sky == 0) {
        check(pro_catg=XSH_GET_TAG_FROM_ARM(XSH_THEO_TAB_SING,instrument));
     } else {
        check(pro_catg=XSH_GET_TAG_FROM_ARM(XSH_SKY_TAB_SING,instrument));
     }
  } else {
     if(sky == 0) {
        check(pro_catg=XSH_GET_TAG_FROM_ARM(XSH_THEO_TAB_MULT,instrument));
     } else {
        check(pro_catg=XSH_GET_TAG_FROM_ARM(XSH_SKY_TAB_MULT,instrument));
     }
  }
  sprintf(THE_filename,"%s%s",pro_catg,".fits");


  check(THE_frm=xsh_model_THE_create(p_xs_3_config,instrument,line_list,
				     num_ph,-1,THE_filename));

  check(plist=cpl_propertylist_load(THE_filename,0));
  check(tab=cpl_table_load(THE_filename,1,0));

  if(!cpl_propertylist_has(plist,XSH_WIN_BINX)) {
    cpl_propertylist_append_int(plist,XSH_WIN_BINX,binx);
  }


  if(!cpl_propertylist_has(plist,XSH_WIN_BINY)) {
    cpl_propertylist_append_int(plist,XSH_WIN_BINY,biny);
  }

  if ( xsh_instrument_get_arm(instrument) == XSH_ARM_UVB){
    seq_arm="UVB     ";
  } else if ( xsh_instrument_get_arm(instrument) == XSH_ARM_VIS){
    seq_arm="VIS     ";
  } else if ( xsh_instrument_get_arm(instrument) == XSH_ARM_NIR){
    seq_arm="NIR     ";
  }

  if(!cpl_propertylist_has(plist,XSH_SEQ_ARM)) {
    cpl_propertylist_append_string(plist,XSH_SEQ_ARM,seq_arm);
  }


  check(xsh_pfits_set_pcatg(plist,pro_catg ) ) ;

  check(cpl_table_save(tab,plist,NULL,THE_filename,CPL_IO_DEFAULT));
  xsh_free_table(&tab);
  xsh_free_propertylist(&plist);

  check(cpl_frame_set_filename(THE_frm,THE_filename));

  check(xsh_frame_config(THE_filename,pro_catg,CPL_FRAME_TYPE_TABLE, 
                         CPL_FRAME_GROUP_PRODUCT,CPL_FRAME_LEVEL_FINAL,
                         &THE_frm));
 
  if(num_ph == 1) {
    check(tab=cpl_table_load(THE_filename,1,0));
    check(plist=cpl_propertylist_load(THE_filename,0));
    pslit_index=cpl_table_get_data_int(tab,"slit_index");
    for(i=0;i<cpl_table_get_nrow(tab);i++){
      pslit_index[i]=4;
    }
    check(cpl_table_save(tab,plist,NULL,THE_filename,CPL_IO_DEFAULT));
    xsh_free_table(&tab);
    xsh_free_propertylist(&plist);
  }
  xsh_msg("model THE table corresponding to optimized configuration %s %s",
	  cpl_frame_get_filename(THE_frm),
	  cpl_frame_get_tag(THE_frm));


 cleanup:

  xsh_free_propertylist(&plist);
  xsh_free_table(&tab);
  //  xsh_pre_free( &pre_sci);
  if(cpl_error_get_code() == CPL_ERROR_NONE) {
    return THE_frm;
  } else {
    xsh_free_frame(&THE_frm);
    xsh_print_rec_status(0);
    return NULL;
  }


}

/*--------------------------------------------------------------------------*/
/**
   @name xsh_model_temperature_update 
   @brief update model structure for current frame temperature 
   @param  p_xs_3_config pointer to model structure
   @param  ref_frame  frame reference for temperature
   @return CPL_ERROR_NONE if no problem occurred
*/
/*--------------------------------------------------------------------------*/
cpl_error_code
xsh_model_temperature_update_structure(struct xs_3* p_xs_3_config,
                                       cpl_frame* ref_frame,
                                       xsh_instrument* instrument)
{
 double zeroK=-273.15;
 const char* ref_name=NULL;
 cpl_propertylist* ref_head=NULL;
 check(ref_name=cpl_frame_get_filename(ref_frame));
 check(ref_head=cpl_propertylist_load(ref_name,0));

   /*Update prism temperature(s) before call to phys mod so that predicted
     positions are for actual frame exposure prism temperature(s)
     UVB,VIS temperatures are in C, NIR ones are in K
    */

   if (xsh_instrument_get_arm(instrument)==XSH_ARM_VIS) { 
      p_xs_3_config->temper=xsh_pfits_get_temp5(ref_head)-zeroK;
   } 
   else if (xsh_instrument_get_arm(instrument)==XSH_ARM_UVB) { 
      p_xs_3_config->temper=xsh_pfits_get_temp2(ref_head)-zeroK;
      p_xs_3_config->fdet=252.56094+(float)(xsh_pfits_get_FOCU1ENC(ref_head))*0.00034065216;
   } 
   else if (xsh_instrument_get_arm(instrument)==XSH_ARM_NIR) { 
      p_xs_3_config->temper=xsh_pfits_get_temp82(ref_head);
      p_xs_3_config->t_ir_p2=xsh_pfits_get_temp82(ref_head);
      p_xs_3_config->t_ir_p3=xsh_pfits_get_temp82(ref_head);
   } 

  cleanup:
  xsh_free_propertylist(&ref_head);
   return cpl_error_get_code();
}
/*--------------------------------------------------------------------------*/
/**
   @name xsh_model_temperature_update 
   @brief update model frame table for current frame temperature 
   @param  model_config_frame input model configuration frame table
   @param  ref_frame  ref frame (to get Temperature from)
   @return CPL_ERROR_NONE if no problem occurred
*/
/*--------------------------------------------------------------------------*/
cpl_error_code
xsh_model_temperature_update_frame(cpl_frame** model_config_frame,
                                   cpl_frame* ref_frame,
                                   xsh_instrument* instrument,
                                   int* found_temp)
{
   double zeroK=-273.15;
   const char* cfg_name=NULL;
   const char* ref_name=NULL;
   cpl_table* cfg_tab=NULL;
   cpl_propertylist* cfg_head=NULL;
   cpl_propertylist* ref_head=NULL;
   double focu1enc=0.0;
   double old_focu1enc=0.0;
   double old_fdet=0.0;
   double temp2=0;
   double temp5=0;
   double temp82=0;
   char local_cfg_name[256];

   /*Update prism temperature(s) before call to phys mod so that predicted
     positions are for actual frame exposure prism temperature(s)
     UVB,VIS temperatures are in C, NIR ones are in K
    */

   check(cfg_name=cpl_frame_get_filename(*model_config_frame));
   check(ref_name=cpl_frame_get_filename(ref_frame));
   check(ref_head=cpl_propertylist_load(ref_name,0));
   //xsh_msg("name=%s",cfg_name);
   check(cfg_tab=cpl_table_load(cfg_name,1,0));
   check(cfg_head=cpl_propertylist_load(cfg_name,0));
   sprintf(local_cfg_name,"local_cfg_name_%s.fits",
           xsh_instrument_arm_tostring( instrument ));
   /*update config with fdet from data header */
   if (xsh_instrument_get_arm(instrument) == XSH_ARM_UVB) {
     check(old_fdet=cpl_table_get_double(cfg_tab,"Best_Guess",36,NULL));
     focu1enc=(float)(xsh_pfits_get_FOCU1ENC(ref_head));
     old_focu1enc=(float)(xsh_pfits_get_FOCU1ENC(cfg_head));
     if(cpl_error_get_code() != CPL_ERROR_NONE) {
       xsh_msg_warning("FITS key %s not found",XSH_FOCU1ENC_VAL);
       xsh_msg_warning("We cannot update the UVB camera focal length");
       *found_temp=false;
       cpl_error_reset();
     } else {
       //       xsh_msg("XSH_FOCU1ENC_VAL =%f ( %f )",focu1enc,252.56094+focu1enc*0.00034065216);
       xsh_msg("XSH_FOCU1ENC_VAL =%f ( %f )",focu1enc,old_fdet+(focu1enc-old_focu1enc)*0.00034065216);
     }
     //     check(cpl_table_set_double(cfg_tab,"Best_Guess",36,252.56094+focu1enc*0.00034065216));
     check(cpl_table_set_double(cfg_tab,"Best_Guess",36,old_fdet+(focu1enc-old_focu1enc)*0.00034065216));
   }
   /*update config with temperatures from data header */
   if (xsh_instrument_get_arm(instrument) == XSH_ARM_VIS) {
     temp5=xsh_pfits_get_temp5(ref_head);
     if(cpl_error_get_code() != CPL_ERROR_NONE) {
       xsh_msg_warning("FITS key %s not found or outside of expected range",
		       XSH_TEMP5_VAL);
       xsh_msg_warning("We cannot update the prism temperatures");
       *found_temp=false;
       cpl_error_reset();
     } else {
       xsh_msg("XSH_TEMP5_VAL=%f [C]",temp5);
     }
     check(cpl_table_set_double(cfg_tab,"Best_Guess",1,temp5-zeroK));
   }
   else if (xsh_instrument_get_arm(instrument) == XSH_ARM_UVB) {
     temp2=xsh_pfits_get_temp2(ref_head);
     if(cpl_error_get_code() != CPL_ERROR_NONE) {
       xsh_msg_warning("FITS key %s not found or outside of expected range",
		       XSH_TEMP2_VAL);
       xsh_msg_warning("We cannot update the prism temperatures");
       *found_temp=false;
       cpl_error_reset();
     } else {
       xsh_msg("XSH_TEMP2_VAL=%f [C]",temp2);
     }
     check(cpl_table_set_double(cfg_tab,"Best_Guess",1,temp2-zeroK));
   }
   else if (xsh_instrument_get_arm(instrument) == XSH_ARM_NIR) {
     temp82=xsh_pfits_get_temp82(ref_head);
     /* extra check: some com data miss or have wrong temperature */
     if(cpl_error_get_code() != CPL_ERROR_NONE || temp82 >200.0) {
       xsh_msg_warning("FITS key %s not found or outside of expected range",
		       XSH_TEMP82_VAL);
       xsh_msg_warning("We cannot update the prism temperatures");
       *found_temp=false;
       cpl_error_reset();
       temp82=105.0;
     } else {
       xsh_msg("XSH_TEMP82_VAL=%f [K]",temp82);
     }
     check(cpl_table_set_double(cfg_tab,"Best_Guess",1,temp82));
     check(cpl_table_set_double(cfg_tab,"Best_Guess",2,temp82));
     check(cpl_table_set_double(cfg_tab,"Best_Guess",3,temp82));
   }
   check(cpl_table_save(cfg_tab, cfg_head, NULL, local_cfg_name, CPL_IO_DEFAULT));
   cpl_frame_set_filename(*model_config_frame,local_cfg_name);
   xsh_add_temporary_file(local_cfg_name);

  cleanup:
   xsh_free_table(&cfg_tab);
   xsh_free_propertylist(&cfg_head);
   xsh_free_propertylist(&ref_head);

   return cpl_error_get_code();

}
