/* $Id: fors_utils.h,v 1.31 2013-07-24 09:56:58 cgarcia Exp $
 *
 * This file is part of the FORS Library
 * Copyright (C) 2002-2010 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 */

/*
 * $Author: cgarcia $
 * $Date: 2013-07-24 09:56:58 $
 * $Revision: 1.31 $
 * $Name: not supported by cvs2svn $
 */

#ifndef FORS_UTILS_H
#define FORS_UTILS_H

#include <fors_setting.h>
#include <fors_star.h>

#include <cpl.h>

/**
 * @brief  error handling macro
 * @param  condition   boolean expression to evaluate
 * @param  action      statement to execute if condition fails
 * @param  message     error message, or NULL
 */
#define assure(condition, action, ...)                      \
do if (!(condition)) {                                      \
    cpl_error_set_message(cpl_func,                         \
              cpl_error_get_code() ?            \
              cpl_error_get_code() :            \
                          CPL_ERROR_UNSPECIFIED,            \
                          __VA_ARGS__);                     \
    cleanup;                                                \
    action;                                                 \
} while(0)
//    fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n");

/**
 * @brief   error handling macro, allowing to set an error code
 * @param   condition   boolean expression to evaluate
 * @param   errc        error code
 * @param   action      statement to execute if condition fails
 * @param   message     error message, or NULL
 * 
 * Created on Feb 04, 2009, to allow specific error code.
 * FIXME: replace assure() by two different macros:
 * 1. this one
 * 2. one that checks the error state, and so does not take
 *    neither a condition nor an error code
 */
#define cassure(condition, errc, action, ...)               \
do if (!(condition)) {                                      \
    cpl_error_set_message(                  cpl_func,       \
                                            errc,           \
                                            __VA_ARGS__);   \
    cleanup;                                                \
    action;                                                 \
} while(0)
//    fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n");

/**
 * @brief   error handling macro, allowing to set an error code
 * @param   condition   boolean expression to evaluate
 * @param   errc        error code
 * @param   action      statement to execute if condition fails
 * 
 * Created on Feb 05, 2009, to allow specific error code.
 * FIXME: replace assure() by two different macros:
 * 1. this one
 * 2. one that checks the error state, and so does not take
 *    neither a condition nor an error code
 */
#define cassure_automsg(condition, errc, action)            \
do if (!(condition)) {                                      \
    cpl_error_set_message(                  cpl_func,       \
                                            errc,           \
                                            "!("#condition")");\
    cleanup;                                                \
    action;                                                 \
} while(0)
//    fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n");

/**
 * @brief  assertion failure
 * @param  condition   boolean expression to evaluate
 * @param  action      statement to execute if condition fails
 *
 * This macro is like C's assert(), but instead of terminating
 * the process, the user is asked to submit a bug report to the
 * package maintainer.
 */
#define passure(condition, action)                                     \
    assure(condition, action,                                          \
       "Internal error. Please report to %s", PACKAGE_BUGREPORT)

/**
 * @brief  assertion failure
 * @param  condition   boolean expression to evaluate
 * @param  action      statement to execute if condition fails
 *
 * This macro is like C's assert(), but instead of terminating
 * the process, the user is asked to submit a bug report to the
 * package maintainer.
 */
#define ppassure(condition, errc, action)                              \
    cassure(condition, errc, action,                                   \
       "Internal error (!(%s)). Please report to %s", \
       #condition, \
       PACKAGE_BUGREPORT)

#define fors_msg(level, ...) fors_msg_macro(level, cpl_func, __VA_ARGS__)

#ifndef M_PI 
#define M_PI 3.1415926535897932384626433832795
#endif

#ifndef M_E
#define M_E  2.7182818284590452354
#endif

#define TWOSQRT2LN2 2.35482004503095

CPL_BEGIN_DECLS

extern const double STDEV_PR_MAD;

void fors_print_banner(void);
const char * fors_get_license(void);
int fors_get_version_binary(void);
double fors_rand_gauss(void);

double fors_tools_get_kth_double(double *a, int n, int k);
float fors_tools_get_kth_float(float *a, int n, int k);
float fors_tools_get_median_float( float *a, int n);
float fors_tools_get_median_fast_float(float *a, int n)  ;
double fors_utils_median_corr(int n);

void fors_frameset_print(const cpl_frameset *frames);
void fors_frame_print(const cpl_frame *f);
const char *fors_frame_get_type_string(const cpl_frame *f);
const char *fors_frame_get_group_string(const cpl_frame *f);
const char *fors_frame_get_level_string(const cpl_frame *f);
cpl_frameset *fors_frameset_extract(const cpl_frameset *frames,
				    const char *tag);
const char *fors_type_get_string(cpl_type type);
void fors_parameterlist_set_defaults(cpl_parameterlist *parlist);

#ifdef CPL_IS_NOT_CRAP
#else
cpl_image *fors_imagelist_collapse_create(const cpl_imagelist *ilist);
cpl_image *fors_imagelist_collapse_median_create(const cpl_imagelist *ilist);
#endif

double fors_angle_diff(const double *a1, const double *a2);

void fors_msg_macro(cpl_msg_severity level, const char *fct, const char *format, ...)
#ifdef __GNUC__
__attribute__((format (printf, 3, 4)))
#endif
;
#endif

CPL_END_DECLS
