/*                                                                           a
 *   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-15 08:10:37 $
 * $Revision: 1.114 $
 * $Name: not supported by cvs2svn $
 */
#ifndef XSH_UTILS_H
#define XSH_UTILS_H

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

#include <cpl.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <xsh_globals.h>
#include <xsh_data_grid.h>
#include <xsh_utils_polynomial.h>
#include <xsh_data_instrument.h>
#include <xsh_parameters.h>

#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif

#define XSH_MAX(A,B)\
  A > B ? A : B
 
#define XSH_MALLOC( POINTER, TYPE, SIZE) \
  assure(POINTER == NULL, CPL_ERROR_ILLEGAL_OUTPUT,\
    "Try to allocate non NULL pointer");\
  POINTER = (TYPE*)(cpl_malloc(SIZE*sizeof(TYPE)));\
  assure (POINTER != NULL, CPL_ERROR_ILLEGAL_OUTPUT,\
    "Memory allocation failed!")

#define XSH_CALLOC( POINTER, TYPE, SIZE) \
  assure(POINTER == NULL, CPL_ERROR_ILLEGAL_OUTPUT,\
    "Try to allocate non NULL pointer");\
  POINTER = (TYPE*)(cpl_calloc(SIZE,sizeof(TYPE)));\
  assure (POINTER != NULL, CPL_ERROR_ILLEGAL_OUTPUT,\
    "Memory allocation failed!")

#define XSH_REALLOC( POINTER, TYPE, SIZE ) \
  assure(POINTER != NULL, CPL_ERROR_ILLEGAL_INPUT,\
    "Try to re-allocate NULL pointer") ;\
  POINTER = (TYPE *)cpl_realloc(POINTER,SIZE*sizeof(TYPE)));\
  assure( POINTER != NULL, CPL_ERROR_ILLEGAL_OUTPUT,\
    "Memory re-allocation failed!")

#define XSH_NEW_PROPERTYLIST( POINTER) \
  assure(POINTER == NULL, CPL_ERROR_ILLEGAL_OUTPUT,\
    "Try to allocate non NULL pointer");\
  POINTER = cpl_propertylist_new();\
  assure (POINTER != NULL, CPL_ERROR_ILLEGAL_OUTPUT,\
    "Memory allocation for propertylist failed!")

#define XSH_NEW_FRAME( POINTER) \
  assure(POINTER == NULL, CPL_ERROR_ILLEGAL_OUTPUT,\
    "Try to allocate non NULL pointer");\
  POINTER = cpl_frame_new();\
  assure (POINTER != NULL, CPL_ERROR_ILLEGAL_OUTPUT,\
    "Memory allocation for frame failed!")

#define XSH_NEW_FRAMESET( POINTER) \
  assure(POINTER == NULL, CPL_ERROR_ILLEGAL_OUTPUT,\
    "Try to allocate non NULL pointer");\
  POINTER = cpl_frameset_new();\
  assure (POINTER != NULL, CPL_ERROR_ILLEGAL_OUTPUT,\
    "Memory allocation for frameset failed!")


#define XSH_FREE(POINTER)\
  if(POINTER!=NULL) cpl_free(POINTER);\
  POINTER = NULL

#define XSH_PREFIX(prefix,name,instr) \
  XSH_FREE(prefix);\
  prefix = xsh_stringcat_any(name,"_",\
                              xsh_instrument_arm_tostring(instr ),\
                              "" ) ;\
  XSH_ASSURE_NOT_NULL(prefix)

#define XSH_MODE_PREFIX(prefix,name,instr) \
  XSH_FREE(prefix);\
  prefix = xsh_stringcat_any(name,"_",\
                              xsh_instrument_mode_tostring(instr ),\
                              "_",\
                              xsh_instrument_arm_tostring(instr ),\
                              "" ) ;\
  XSH_ASSURE_NOT_NULL(prefix)


#define XSH_TABLE_NEW_COL(TABLE, NAME, UNIT, TYPE) \
  check( cpl_table_new_column(TABLE, NAME, TYPE));\
  check( cpl_table_set_column_unit( TABLE, NAME, UNIT))

#define BOOLEAN_TO_STRING( boolean) \
 boolean == 0 ? "false" : "true"
typedef struct{
  void* data;
  int idx;
}xsh_sort_data;


/*
  Structure to return gaussian fit results
*/
typedef struct {
  double peakpos,
    sigma,
    area,
    offset,
    mse ;
} XSH_GAUSSIAN_FIT ;

enum {
  XSH_DEBUG_LEVEL_NONE, XSH_DEBUG_LEVEL_LOW,
  XSH_DEBUG_LEVEL_MEDIUM, XSH_DEBUG_LEVEL_HIGH
} ;


/*----------------------------------------------------------------------------
 INLINE FONCTIONS (could not be used outside the library)
----------------------------------------------------------------------------*/
long xsh_round_double(double x);
double xsh_max_double(double x, double y);
double xsh_pow_int(double x, int y);



/*----------------------------------------------------------------------------
  Prototypes
----------------------------------------------------------------------------*/
void xsh_random_init(void);
int
xsh_get_random_int_window(const int v1, const int v2);
double
xsh_get_random_double_window(const double v1, const double v2);

cpl_frame* xsh_frame_inv( cpl_frame* in, const char *filename,
  xsh_instrument* instr);

cpl_frame* xsh_frame_abs(  cpl_frame* in,  xsh_instrument* instr,
  cpl_frame** sign);

cpl_frame* xsh_frame_mult(  cpl_frame* in,  xsh_instrument* instr,
  cpl_frame* sign);

cpl_parameterlist* 
xsh_parameterlist_duplicate(const cpl_parameterlist* pin);

void
xsh_plist_dump(cpl_propertylist *plist);

cpl_error_code 
xsh_frameset_dump(cpl_frameset* set);

char * xsh_get_basename(const char *filename);

const char * xsh_get_license(void) ;
void xsh_init(void);

int xsh_min_int(int x, int y);
int xsh_max_int(int x, int y);

void xsh_free(const void *mem);

void xsh_free_temporary_files(void);
cpl_error_code xsh_end(const char *recipe_id, cpl_frameset *frames,
		       cpl_parameterlist * list );
cpl_error_code xsh_begin(cpl_frameset *frames, 
			 const cpl_parameterlist *parameters,
			 xsh_instrument ** instr,
			 cpl_frameset ** raws, cpl_frameset ** calib,
			 const char * tag_list[],
                         int tag_list_size,
			 const char *recipe_id, 
			 unsigned int binary_version, const char *short_descr);
void xsh_add_temporary_file( const char *name ) ;

cpl_error_code xsh_get_property_value(const cpl_propertylist *plist,
				      const char *keyword, cpl_type keywordtype, void *result);

char *xsh_sdate_utc( time_t * t ) ;

char *xsh_stringdup  (const char *s1);
char *xsh_stringcat  (const char *s1, const char *s2);
char *xsh_stringcat_3(const char *s1, const char *s2, const char *s3);
char *xsh_stringcat_4(const char *s1, const char *s2, const char *s3, 
		      const char *s4);
char *xsh_stringcat_5(const char *s1, const char *s2, const char *s3, 
		      const char *s4, const char *s5);
char *xsh_stringcat_6(const char *s1, const char *s2, const char *s3,
		      const char *s4, const char *s5, const char *s6);
char *xsh_stringcat_any( const char *s, ...) ;
void xsh_reindex(double* data, int* idx, int size);
void xsh_reindex_float( float * data, int* idx, int size);
void xsh_reindex_int( int * data, int* idx, int size);
int* xsh_sort(void* base, size_t nmemb, size_t size,
	      int (*compar)(const void *, const void *));
void xsh_tools_min_max(int size, double *tab, double* min, double* max);
void xsh_tools_get_statistics(double* tab, int size, double* median,
  double* mean, double* stdev);

void xsh_free_table(cpl_table **t);
void xsh_free_image(cpl_image **i);
void xsh_free_mask(cpl_mask **m);
void xsh_free_imagelist(cpl_imagelist **i);
void xsh_free_propertylist(cpl_propertylist **p);
void xsh_free_polynomial(cpl_polynomial **p);
void xsh_free_matrix(cpl_matrix **m);
void xsh_free_array(cpl_array **v);
void xsh_free_vector(cpl_vector **v);
void xsh_free_stats(cpl_stats **s);
void xsh_unwrap_image( cpl_image **i);
void xsh_unwrap_vector(cpl_vector **v);
void xsh_unwrap_array(cpl_array **a);
void xsh_unwrap_bivector_vectors(cpl_bivector **b);
void xsh_free_parameterlist(cpl_parameterlist **p);
void xsh_free_parameter(cpl_parameter **p);
void xsh_free_frameset(cpl_frameset **f);
void xsh_free_frame(cpl_frame **f);

void xsh_show_time( const char * comment ) ;

cpl_error_code xsh_tools_sort_double( double * pix_arr, int size ) ;
cpl_error_code xsh_tools_sort_float( float * pix_arr, int size ) ;
cpl_error_code xsh_tools_sort_int( int * pix_arr, int size ) ;
void xsh_tools_tchebitchev_transform_tab(int size, double* pos, double min, 
					 double max, double* tcheb_pos);
double xsh_tools_tchebitchev_transform(double pos, double min,
				       double max);
double xsh_tools_tchebitchev_reverse_transform(double pos, double min,
					       double max);

cpl_vector* xsh_tools_tchebitchev_poly_eval( int n, double X);
double xsh_tools_get_median_double( double *array, int size ) ;
int xsh_tools_running_median_1d_get_max( double * tab, int size, int wsize ) ;

void xsh_image_fit_spline(cpl_image* img, xsh_grid* grid);

void xsh_vector_fit_gaussian( cpl_vector * x, cpl_vector * y,
			      XSH_GAUSSIAN_FIT * result ) ;
double xsh_vector_get_err_median( cpl_vector *vect);
double xsh_vector_get_err_mean( cpl_vector *vect);

int xsh_debug_level_set( int level ) ;
int xsh_debug_level_get( void ) ;
const char * xsh_debug_level_tostring( void ) ;

int xsh_time_stamp_set( int ts ) ;
int xsh_time_stamp_get( void ) ;

void xsh_mem_dump( const char * prompt) ;
cpl_image * xsh_imagelist_collapse_sigclip_iter_create(
        const cpl_imagelist *   imlist,
        double                  sigma_low,
        double                  sigma_upp,
        const int               niter);

double convert_bin_to_data( double bin_data, int binning);
double convert_data_to_bin( double data, int binning);

cpl_frameset * xsh_order_frameset_by_date( cpl_frameset * frameset ) ;

cpl_error_code xsh_set_cd_matrix(cpl_propertylist* plist);
cpl_error_code xsh_set_cd_matrix1d(cpl_propertylist* plist);
cpl_error_code xsh_set_cd_matrix2d(cpl_propertylist* plist);
cpl_error_code xsh_set_cd_matrix3d(cpl_propertylist* plist);
int xsh_erase_table_rows(cpl_table *t, const char *column, 
              cpl_table_select_operator operator,
              double value);
int xsh_select_table_rows(cpl_table *t,  const char *column,
                      cpl_table_select_operator operator, 
                      double value);


polynomial *
xsh_polynomial_regression_2d(cpl_table *t,
                  const char *X1, const char *X2, const char *Y, 
                  const char *sigmaY,
                  int degree1, int degree2,
                  const char *polynomial_fit, const char *residual_square, 
                  const char *variance_fit,
                  double *mse, double *red_chisq,
                  polynomial **variance, double kappa,
                              double min_reject);
cpl_error_code
xsh_check_input_is_unbinned(cpl_frame* in);

cpl_error_code
xsh_update_pheader_in_image_multi(cpl_frame *frame, 
                                  const cpl_propertylist* pheader);


cpl_error_code
xsh_monitor_flux(cpl_frame* frm_ima,const cpl_frame* frm_tab,
  xsh_instrument* instrument);
cpl_error_code 
xsh_frameset_dump_nod_info(cpl_frameset* set);
void
xsh_frame_spectrum_save(cpl_frame* frm,const char* name_o);
void
xsh_frame_image_save(cpl_frame* frm,const char* name_o);

void
xsh_frame_table_save(cpl_frame* frm,const char* name_o);

char* 
xsh_set_recipe_file_prefix(cpl_frameset* raw,const char* recipe);
const char* 
xsh_set_recipe_sky_file_prefix(char* rec_prefix);
cpl_frame* 
xsh_frameset_average(cpl_frameset *set, const char* tag);
cpl_frame* xsh_frameset_add( cpl_frameset *set, xsh_instrument *instr,const int decode_bp);

int xsh_fileutils_move (const char *srcpath, const char *dstpath);
int xsh_fileutils_copy (const char * srcpath, const char * dstpath);
void xsh_add_product_file( const char *name);
void xsh_free_product_files( void);
const char* xsh_string_tolower(char* s);
const char* xsh_string_toupper(char* s);
double 
xsh_spline_hermite_table( double xp, const cpl_table *t, const char *column_x, 
                          const char *column_y, int *istart );
double 
xsh_spline_hermite( double xp, const double *x, const double *y, int n, int *istart );
cpl_frame*
xsh_util_multiply_by_response(cpl_frame* merged_sci, cpl_frame* response,
                              const char* tag);

cpl_frame*
xsh_util_multiply_by_response_ord(cpl_frame* merged_sci, cpl_frame* response,
                              const char* tag);

cpl_frame*
xsh_util_frameset_collapse_mean(cpl_frameset* set,
                                xsh_instrument* instrument);

cpl_frame* 
xsh_spectrum_resample(cpl_frame* frame_inp, 
                      const double wstep, 
                      const double wmin,
                      const double wmax, 
		      xsh_instrument* instr);

cpl_frame* 
xsh_spectrum_resample2(cpl_frame* frame_inp, 
                      const double wstep, 
                      const double wmin,
                      const double wmax, 
		      xsh_instrument* instr);


cpl_frame*
xsh_spectrum_interpolate(cpl_frame* table_frame,
                       const double wstep,
                       const double wmin,
                       const double wmax);

cpl_frame*
xsh_spectrum_interpolate_linear(cpl_frame* table_frame,
                       const double wstep,
                       const double wmin,
                       const double wmax);

cpl_image*
xsh_vector_to_image(const cpl_vector* vector,cpl_type type);
cpl_vector * 
xsh_image_to_vector( cpl_image * spectrum );

cpl_image *
xsh_normalize_spectrum_image(const cpl_image *spectrum, 
                             const cpl_image *spectrum_error,
                             const cpl_propertylist *spectrum_header,
                             const int binx, 
                             const double gain, 
                             const double exptime,
                             const double airmass,
                             const int n_traces,
                             const cpl_table *atm_extinction,
                             cpl_image **scaled_error);

cpl_frame *
xsh_normalize_spectrum(const cpl_frame *obj_frame, 
                       const cpl_frame *atm_ext_frame,
                       cpl_boolean correct_binning,
                       xsh_instrument* instrument,
                       const char* tag);

cpl_frame *
xsh_normalize_spectrum_ord(const cpl_frame *obj_frame, 
                       const cpl_frame *atm_ext_frame,
                       cpl_boolean correct_binning,
                       xsh_instrument* instrument,
                       const char* tag);

void xsh_array_clip_mean( cpl_array *array, double kappa, int niter,
  double frac_min, double *mean, double *stdev);

void xsh_array_clip_median( cpl_array *array, double kappa, int niter,
  double frac_min, double *median, double *stdev);

void xsh_array_clip_poly1d( cpl_vector *pos_array, cpl_vector *val_array, 
  double kappa, int niter, double frac_min, int deg, cpl_polynomial **poly, 
  double *chisq, int **flags);

cpl_error_code 
xsh_rectify_params_set_defaults(cpl_parameterlist* pars,
                                const char* rec_id,
                                xsh_instrument* inst,
                                xsh_rectify_param * rectify_par);

void xsh_gsl_init_gaussian_fit( cpl_vector *xpos_vect, cpl_vector *ypos_vect,
  double *init_par);
void xsh_gsl_fit_gaussian( cpl_vector *xpos_vect, cpl_vector *ypos_vect, int deg,
  double *params, double *errs, int *status);

double xsh_hms2deg(const double hms);
double xsh_sess2deg(const double sess);

double*
xsh_function1d_xcorrelate(
    double *    line_i,
    int         width_i,
    double *    line_t,
    int         width_t,
    int         half_search,
    int normalise,
    double *    xcorr_max,
    double *    delta
			  );

#endif
