/*                                                                           *
 *   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-07-12 14:54:48 $
 * $Revision: 1.38 $
 * $Name: not supported by cvs2svn $
 */
#ifndef XSH_DATA_INSTRUMENT_H
#define XSH_DATA_INSTRUMENT_H

/*---------------------------------------------------------------------------
                                    Includes
 ----------------------------------------------------------------------------*/
#include <cpl.h>

/*---------------------------------------------------------------------------
                            Typedefs
  ---------------------------------------------------------------------------*/
/*
#define XSH_RAW_NAXIS2_UVB 3000
#define XSH_RAW_NAXIS2_VIS 4000
#define XSH_RAW_NAXIS2_NIR 2048
*/
#define XSH_ORDERS_NIR 16
#define XSH_ORDER_MIN_NIR 11
#define XSH_ORDER_MAX_NIR 26

#define XSH_ORDERS_UVB 12
#define XSH_ORDERS_UVB_QTH 8
#define XSH_ORDERS_UVB_D2 4

#define XSH_ORDER_MIN_UVB 13
#define XSH_ORDER_MAX_UVB 24
#define XSH_ORDER_MIN_UVB_D2 21
#define XSH_ORDER_MAX_UVB_D2 XSH_ORDER_MAX_UVB
#define XSH_ORDER_MIN_UVB_QTH XSH_ORDER_MIN_UVB
#define XSH_ORDER_MAX_UVB_QTH XSH_ORDER_MIN_UVB_D2 -1

#define XSH_ORDERS_VIS 15
#define XSH_ORDER_MIN_VIS 16
#define XSH_ORDER_MAX_VIS 30

#define XSH_ORDERS_UNDEFINED 0

#define XSH_NB_PINHOLE 9

/* Arc seconds per pixel */
#define XSH_ARCSEC_NIR 0.2
#define XSH_ARCSEC_UVB 0.14
#define XSH_ARCSEC_VIS 0.135

/* Slit dimension in SLIT mode (unit=arcsecond)*/
#if 0
#define MIN_SLIT -5.5
#define MAX_SLIT 5.5
#else
#define MIN_SLIT -5.3
#define MAX_SLIT 5.7
#endif
#define LENGTH_SLIT 11.
#define BASE_MIN_SLIT -5.5
#define BASE_MAX_SLIT 5.5

/* Slit dimension in IFU mode (unit=arcsecond) */
#define MIN_SLIT_IFU -6.0
#define MAX_SLIT_IFU 6.0
#define LENGTH_SLIT_IFU 12
#define WIDTH_SLIT_IFU 0.6

#define CHECK_POS_IN_SLIT( pos)\
  if ( (pos < MIN_SLIT_IFU) || (pos > MAX_SLIT_IFU)){\
    xsh_error_msg( "Invalid slit position %f : not in [%f,%f]"\
      ,pos, MIN_SLIT_IFU, MAX_SLIT_IFU);\
  }

/* Mapping of IFU co-ordinates to entrance slit co-ordinates (mm) */
#define IFU_SCALE 0.03925
#define IFU_MAP_LEFT_C0X (-0.6*IFU_SCALE)//-10.10
#define IFU_MAP_LEFT_C1X -1.0//-58.81
#define IFU_MAP_LEFT_C2X 0.0//-85.17
#define IFU_MAP_CEN_C0X 0.0//0.0
#define IFU_MAP_CEN_C1X 1.0//0.98
#define IFU_MAP_CEN_C2X 0.0//7.01
#define IFU_MAP_RIGHT_C0X (0.6*IFU_SCALE)//7.4
#define IFU_MAP_RIGHT_C1X -1.0//-41.25
#define IFU_MAP_RIGHT_C2X 0.0//57.55

#define IFU_MAP_LEFT_C0Y (4.0*IFU_SCALE)//2.13
#define IFU_MAP_LEFT_C1Y -1.0
#define IFU_MAP_LEFT_C2Y 0.0
#define IFU_MAP_CEN_C0Y 0.0
#define IFU_MAP_CEN_C1Y 1.0
#define IFU_MAP_CEN_C2Y 0.0
#define IFU_MAP_RIGHT_C0Y (-4.0*IFU_SCALE)//-2.09
#define IFU_MAP_RIGHT_C1Y -1.0
#define IFU_MAP_RIGHT_C2Y 0.0

/*IFU slitlet limits in arcsec*/
#define IFU_LOW -2.0 //=-0.5*(11.4/3)
#define IFU_HI 2.0 //=+0.5*(11.4/3)
#define IFU_LEFT_MIN -0.9 //=-1.5*0.6
#define IFU_LEFT_MAX -0.3 //=-0.5*0.6
#define IFU_CEN_MIN -0.3 //=-0.5*0.6
#define IFU_CEN_MAX 0.3 //=+0.5*0.6
#define IFU_RIGHT_MIN 0.3 //=+0.5*0.6
#define IFU_RIGHT_MAX 0.9 //=+1.5*0.6

typedef enum {
  XSH_MODE_IFU,
  XSH_MODE_SLIT,
  XSH_MODE_UNDEFINED
} XSH_MODE;


typedef enum {
  XSH_ARM_UVB,
  XSH_ARM_VIS,
  XSH_ARM_NIR,
  XSH_ARM_AGC,
  XSH_ARM_UNDEFINED
} XSH_ARM;

typedef enum {
  XSH_LAMP_QTH,
  XSH_LAMP_D2,
  XSH_LAMP_THAR,
  XSH_LAMP_QTH_D2,
  XSH_LAMP_UNDEFINED
} XSH_LAMP;

typedef struct {
  int bitpix;
  int naxis;
  int naxis1;
  int naxis2;
  int nx;
  int ny;
  int prscx;
  int prscy;
  int ovscx;
  int ovscy;
  double pszx;
  double pszy;
  double ron;
  double conad;
  double pxspace ;		/**< Needed by NIR frames */
  int orders ;			/**< Number of 'good' orders */
  int order_min ;		/**< First absolute order */
  int order_max ;		/**< Last absolute order */
} XSH_INSTRCONFIG;

typedef struct {
  int uvb_orders_nb;
  int uvb_orders_qth_nb;
  int uvb_orders_d2_nb;
  int uvb_orders_min;
  int uvb_orders_max;
  int vis_orders_nb;
  int vis_orders_min;
  int vis_orders_max;
  int nir_orders_nb;
  int nir_orders_min;
  int nir_orders_max;
  int binx;
  int biny;
  int decode_bp;

  int update;
  XSH_MODE mode;
  XSH_ARM arm;
  XSH_LAMP lamp;
  XSH_INSTRCONFIG* config;
  const char* pipeline_id;
  const char *dictionary;
  const char * recipe_id ;
} xsh_instrument;


#define XSH_NAME_LAMP_MODE_ARM( name, id, ext, instr) \
  XSH_NAME_PREFIX_LAMP_MODE_ARM( name, "", id, ext, instr)
  
#define XSH_NAME_PREFIX_LAMP_MODE_ARM( name, prefix, id, ext, instr)\
  XSH_FREE( name);\
  XSH_ASSURE_NOT_NULL( prefix);\
  if ( xsh_instrument_get_mode( instr) != XSH_MODE_UNDEFINED){\
    if (xsh_instrument_get_lamp( instr) != XSH_LAMP_UNDEFINED){\
      name = xsh_stringcat_any( prefix, id, "_", \
        xsh_instrument_lamp_tostring( instr)\
        , "_", xsh_instrument_mode_tostring( instr),"_", \
        xsh_instrument_arm_tostring( instr), ext, "");\
    }\
    else{\
      name = xsh_stringcat_any( prefix, id, "_",\
        xsh_instrument_mode_tostring( instr),"_", \
        xsh_instrument_arm_tostring( instr), ext, "");\
    }\
  }\
  else{\
    name = xsh_stringcat_any( prefix, id, "_",\
      xsh_instrument_arm_tostring( instr), ext, "");\
  }\
  XSH_ASSURE_NOT_NULL( name)
/*---------------------------------------------------------------------------
                            Methods
  ---------------------------------------------------------------------------*/

/* Create / delete */
xsh_instrument* xsh_instrument_new(void);
void xsh_instrument_free(xsh_instrument** );
xsh_instrument * xsh_instrument_duplicate( xsh_instrument * instrument ) ;
/* Set / Get */
void xsh_instrument_set_mode(xsh_instrument* i,XSH_MODE mode);
void xsh_instrument_set_decode_bp(xsh_instrument* i,const int decode_bp);
void xsh_instrument_set_arm(xsh_instrument* i,XSH_ARM arm);
void xsh_instrument_set_lamp(xsh_instrument* i,XSH_LAMP lamp);
void xsh_instrument_set_recipe_id(xsh_instrument* i, const char *recipe_id);

void xsh_instrument_update_lamp(xsh_instrument* i, XSH_LAMP lamp);
void xsh_instrument_update_from_spectralformat(xsh_instrument* i, 
  cpl_frame* spectralformat_frame);

XSH_MODE xsh_instrument_get_mode(xsh_instrument* i);
XSH_ARM xsh_instrument_get_arm(xsh_instrument* i);
XSH_LAMP xsh_instrument_get_lamp(xsh_instrument* i);
XSH_INSTRCONFIG* xsh_instrument_get_config(xsh_instrument* i);

int xsh_instrument_get_binx( xsh_instrument * instrument ) ;
int xsh_instrument_get_biny( xsh_instrument * instrument ) ;

XSH_ARM xsh_arm_get(const char* tag);
XSH_MODE xsh_mode_get(const char* tag);
XSH_LAMP xsh_lamp_get(const char* tag);

double xsh_arcsec_get( xsh_instrument * instrument ) ;
double xsh_resolution_get( xsh_instrument * instrument, double slit);

/* analyse tags */
void xsh_instrument_parse_tag(xsh_instrument* inst,const char* tag);

/* ToString */
const char* xsh_instrument_mode_tostring(xsh_instrument* i);
const char* xsh_instrument_arm_tostring(xsh_instrument* i);
const char* xsh_instrument_lamp_tostring(xsh_instrument* i);

const char* xsh_mode_tostring(XSH_MODE mode);
const char* xsh_arm_tostring(XSH_ARM arm);
const char* xsh_lamp_tostring(XSH_LAMP lamp);
void xsh_instrument_set_binx( xsh_instrument * instrument, const int binx );
void xsh_instrument_set_biny( xsh_instrument * instrument, const int biny );
void xsh_mode_set(xsh_instrument* instrument, XSH_MODE mode);
cpl_error_code
xsh_instrument_nir_corr_if_JH(cpl_frameset* raws, xsh_instrument* instr);
int
xsh_instrument_nir_is_JH(cpl_frame* frm, xsh_instrument* instr);

cpl_error_code
xsh_instrument_nir_corr_if_spectral_format_is_JH(cpl_frameset* calib, xsh_instrument* instr);
#endif  /* XSH_DATA_INSTRUMENT_H */
