#ifndef VIENNA_RNA_PACKAGE_PROBING_H
#define VIENNA_RNA_PACKAGE_PROBING_H

#include <ViennaRNA/fold_compound.h>

#ifdef VRNA_WARN_DEPRECATED
# if defined(__clang__)
#  define DEPRECATED(func, msg) func __attribute__ ((deprecated("", msg)))
# elif defined(__GNUC__)
#  define DEPRECATED(func, msg) func __attribute__ ((deprecated(msg)))
# else
#  define DEPRECATED(func, msg) func
# endif
#else
# define DEPRECATED(func, msg) func
#endif


/**
 *  @file     ViennaRNA/probing/basic.h
 *  @ingroup  probing_data
 *  @brief    This module provides function to incorporate RNA structure
 *            probing data, e.g. SHAPE reactivities, into the folding recursions
 *            by means of soft constraints
 */

/**
 *  @addtogroup probing_data
 *  @{
 */


/**
 *  @brief  A data structure that contains RNA structure probing data and specifies how this data
 *          is to be integrated into structure predictions
 *
 *  @see    vrna_probing_data_deigan(), vrna_probing_data_deigan_comparative(),
 *          vrna_probing_data_zarringhalam(), vrna_probing_data_zarringhalam_comparative(),
 *          vrna_sc_probing(), vrna_probing_data_free()
 */
typedef struct vrna_probing_data_s *vrna_probing_data_t;


#define VRNA_REACTIVITY_MISSING                                   -999.


/**
 *  @}
 */


/**
 *  @addtogroup probing_data_strategy
 *  @{
 */

#define VRNA_PROBING_DATA_WEIGHT_POSITION_WISE                    (1 << 2)
#define VRNA_PROBING_DATA_SINGLE_STRATEGY                         (1 << 0)
#define VRNA_PROBING_DATA_SINGLE_WEIGHT                           (1 << 1)
#define VRNA_PROBING_DATA_DEFAULT                                 0

#define VRNA_PROBING_DATA_LINEAR_TARGET_STACK                     (1 << 4)
#define VRNA_PROBING_DATA_LINEAR_TARGET_UP                        (1 << 5)
#define VRNA_PROBING_DATA_LINEAR_TARGET_BP                        (1 << 6)


typedef void *vrna_probing_strategy_opt_t;

/**
 *  @brief  Prototype of a strategy to derive pseudo energies from linear structure probing data
 *
 *  @param  fc        The fold compound the probing data will be applied to
 *  @param  data      The structure probing data (1-based array of reactivity values)
 *  @param  data_size The size of @p data, i.e. the total number of reactivity values
 *  @param  target    The structural context for which pseudo energies are requested from the strategy
 *  @param  options   An arbitrary data structure the strategy requires for working on the data
 *  @return           A pointer to an array of pseudo energies ready to be included as soft constraints
 */
typedef double *(*vrna_probing_strategy_f)(vrna_fold_compound_t *fc,
                                           const double         *data,
                                           size_t               data_size,
                                           unsigned int         target,
                                           void                 *options);

/**
 *  @brief probing data conversion flag for comparative structure predictions indicating no parameter to be sequence specific
 *
 *  @see  vrna_probing_data_deigan_comparative(), vrna_probing_data_zarringhalam_comparative(),
 *        #VRNA_PROBING_METHOD_MULTI_PARAMS_1, #VRNA_PROBING_METHOD_MULTI_PARAMS_2, #VRNA_PROBING_METHOD_MULTI_PARAMS_3,
 *        #VRNA_PROBING_METHOD_MULTI_PARAMS_DEFAULT
 */
#define VRNA_PROBING_METHOD_MULTI_PARAMS_0                        0U


/**
 *  @brief probing data conversion flag for comparative structure predictions indicating 1st parameter to be sequence specific
 *
 *  @see  vrna_probing_data_deigan_comparative(), vrna_probing_data_zarringhalam_comparative(),
 *        #VRNA_PROBING_METHOD_MULTI_PARAMS_0, #VRNA_PROBING_METHOD_MULTI_PARAMS_2, #VRNA_PROBING_METHOD_MULTI_PARAMS_3,
 *        #VRNA_PROBING_METHOD_MULTI_PARAMS_DEFAULT
 */
#define VRNA_PROBING_METHOD_MULTI_PARAMS_1                        1U


/**
 *  @brief probing data conversion flag for comparative structure predictions indicating 2nd parameter to be sequence specific
 *
 *  @see  vrna_probing_data_deigan_comparative(), vrna_probing_data_zarringhalam_comparative(),
 *        #VRNA_PROBING_METHOD_MULTI_PARAMS_0, #VRNA_PROBING_METHOD_MULTI_PARAMS_1, #VRNA_PROBING_METHOD_MULTI_PARAMS_3,
 *        #VRNA_PROBING_METHOD_MULTI_PARAMS_DEFAULT
 */
#define VRNA_PROBING_METHOD_MULTI_PARAMS_2                        2U


/**
 *  @brief probing data conversion flag for comparative structure predictions indicating 3rd parameter to be sequence specific
 *
 *  @see  vrna_probing_data_deigan_comparative(), vrna_probing_data_zarringhalam_comparative(),
 *        #VRNA_PROBING_METHOD_MULTI_PARAMS_0, #VRNA_PROBING_METHOD_MULTI_PARAMS_1, #VRNA_PROBING_METHOD_MULTI_PARAMS_2,
 *        #VRNA_PROBING_METHOD_MULTI_PARAMS_DEFAULT
 */
#define VRNA_PROBING_METHOD_MULTI_PARAMS_3                        4U


/**
 *  @brief probing data conversion flag for comparative structure predictions indicating default parameter settings
 *
 *  Essentially, this setting indicates that all probing data is to be converted using the same
 *  parameters. Use any combination of #VRNA_PROBING_METHOD_MULTI_PARAMS_1, #VRNA_PROBING_METHOD_MULTI_PARAMS_2,
 *  #VRNA_PROBING_METHOD_MULTI_PARAMS_3, and so on to indicate that the first, second, third, or other
 *  parameter is sequence specific.
 *
 *  @see vrna_probing_data_deigan_comparative(), vrna_probing_data_zarringhalam_comparative()
 */
#define VRNA_PROBING_METHOD_MULTI_PARAMS_DEFAULT                  VRNA_PROBING_METHOD_MULTI_PARAMS_0


double *
vrna_probing_strategy_chain(vrna_fold_compound_t        *fc,
                            const double                *data,
                            size_t                      data_size,
                            unsigned int                target,
                            vrna_probing_strategy_opt_t options);


vrna_probing_strategy_opt_t
vrna_probing_strategy_chain_data(vrna_probing_strategy_f      strategy_cb,
                                 vrna_probing_strategy_opt_t  strategy_cb_options,
                                 vrna_auxdata_free_f          strategy_cb_options_free);


size_t
vrna_probing_strategy_chain_data_append(vrna_probing_strategy_opt_t chain,
                                        vrna_probing_strategy_f     strategy_cb,
                                        vrna_probing_strategy_opt_t strategy_cb_options,
                                        vrna_auxdata_free_f         strategy_cb_options_free);


size_t
vrna_probing_strategy_chain_data_size(vrna_probing_strategy_opt_t chain);


vrna_probing_strategy_f
vrna_probing_strategy_chain_data_at(vrna_probing_strategy_opt_t chain,
                                    size_t                      pos,
                                    vrna_probing_strategy_opt_t *strategy_cb_options);


void
vrna_probing_strategy_chain_data_free(vrna_probing_strategy_opt_t options);


/**
 *  @}
 */


/**
 *  @addtogroup probing_data
 *  @{
 */


/**
 *  @brief  Apply probing data (e.g. SHAPE) to guide the structure prediction
 *
 *  @see  #vrna_probing_data_t, vrna_probing_data_free(),
 *        vrna_probing_data_deigan(), vrna_probing_data_deigan_comparative(),
 *        vrna_probing_data_zarringhalam(), vrna_probing_data_zarringhalam_comparative(),
 *        vrna_probing_data_eddy(), vrna_probing_data_eddy_comparative()
 *
 *  @param  fc      The #vrna_fold_compound_t the probing data should be applied to in subsequent computations
 *  @param  data    The prepared probing data and probing data integration strategy
 *  @return The number of probing data sets applied, 0 upon any error
 */
int
vrna_sc_probing(vrna_fold_compound_t  *fc,
                vrna_probing_data_t   data);


vrna_probing_data_t
vrna_probing_data_linear(const double             *data,
                         unsigned int             data_length,
                         const double             *data_weights,
                         vrna_probing_strategy_f  strategy_cb,
                         void                     *strategy_cb_options,
                         vrna_auxdata_free_f      strategy_cb_options_free,
                         unsigned int             options);


vrna_probing_data_t
vrna_probing_data_linear_multi(const double             **data,
                               unsigned int             data_size,
                               const unsigned int       *data_lengths,
                               const double             **data_weights,
                               vrna_probing_strategy_f  *strategy_cbs,
                               void                     **strategy_cbs_options,
                               vrna_auxdata_free_f      *strategy_cbs_options_free,
                               unsigned int             options);


/**
 *  @brief  Free memory occupied by the (prepared) probing data
 *
 *  @see    #vrna_probing_data_t, vrna_sc_probing(),
 *          vrna_probing_data_deigan(), vrna_probing_data_deigan_comparative(),
 *          vrna_probing_data_zarringhalam(), vrna_probing_data_zarringhalam_comparative(),
 *          vrna_probing_data_eddy(), vrna_probing_data_eddy_comparative()
 */
void
vrna_probing_data_free(vrna_probing_data_t d);


/**
 *  @brief  Get the number of structure probing data sets
 *
 *  @see vrna_probing_data_linear(), vrna_probing_data_linear_multi()
 *
 *  @param  data  The data structure storing the probing data
 *  @return       The number of probing data sets stored in @p data
 */
unsigned int
vrna_probing_data_linear_num(struct vrna_probing_data_s *data);


/**
 *  @brief  Get the raw probing data
 *
 *  This function retrieves a copy of the structure probing data
 *  set number @p pos as stored in @p data. The number of values
 *  returned by this function is stored in @p data_size.
 *
 *  @see  vrna_probing_data_linear(), vrna_probing_data_linear_multi(),
 *        vrna_probing_data_linear_num(), vrna_probing_data_linear_weight(),
 *        vrna_probing_data_linear_energies()
 *
 *  @param  data      The data structure storing the probing data
 *  @param  pos       The position of the data set
 *  @param  data_size A pointer to a variable to store the number of returned values to
 *  @return           A copy of the @p pos -th probing data set stored in @p data
 */
double *
vrna_probing_data_linear_raw(struct vrna_probing_data_s *data,
                             unsigned int               pos,
                             unsigned int               *data_size);


/**
 *  @brief  Get the weights for a probing data set
 *
 *  @see  vrna_probing_data_linear(), vrna_probing_data_linear_multi(),
 *        vrna_probing_data_linear_num(), vrna_probing_data_linear_raw(),
 *        vrna_probing_data_linear_energies()
 *
 *  @param  data      The data structure storing the probing data
 *  @param  pos       The position of the weights vector
 *  @param  data_size A pointer to a variable to store the number of returned values to
 *  @return           A copy of the @p pos -th weighting vector stored in @p data
 */
double *
vrna_probing_data_linear_weight(struct vrna_probing_data_s  *data,
                                unsigned int                pos,
                                unsigned int                *data_size);


/**
 *  @brief  Get pseudo energy contributions from a structure probing data set
 *
 *  This function retrieves a vector of pseudo energies derived from a set
 *  of structure probing data stored in @p data. For that, the function calls
 *  the probing data strategy that is associated with @p data.
 *
 *  @see  vrna_probing_data_linear(), vrna_probing_data_linear_multi(),
 *        vrna_probing_data_linear_num(), vrna_probing_data_linear_raw(),
 *        vrna_probing_data_linear_weight(), #VRNA_PROBING_DATA_LINEAR_TARGET_STACK,
 *        #VRNA_PROBING_DATA_LINEAR_TARGET_UP, #VRNA_PROBING_DATA_LINEAR_TARGET_BP
 *
 *  @param  data      The data structure storing the probing data
 *  @param  pos       The position of the weights vector
 *  @param  fc        The fold_compound that will be passed through to the conversion strategy
 *  @param  target    The target, i.e. the structure context the pseudo energies should be applied to
 *  @param  data_size A pointer to a variable to store the number of returned values to
 *  @return           An array of pseudo energies (1-based) or @b NULL
 */
double *
vrna_probing_data_linear_energies(struct vrna_probing_data_s  *data,
                                  unsigned int                pos,
                                  vrna_fold_compound_t        *fc,
                                  unsigned int                target,
                                  unsigned int                *data_size);


/**
 *  @brief Convert SHAPE reactivity values to probabilities for being unpaired
 *
 *  This function parses the informations from a given file and stores the result
 *  in the pre-allocated string sequence and the #FLT_OR_DBL array values.
 *
 *  @ingroup SHAPE_reactivities
 *
 *  @see vrna_file_SHAPE_read()
 *
 *  @param shape_conversion String defining the method used for the conversion process
 *  @param values           Pointer to an array of SHAPE reactivities
 *  @param length           Length of the array of SHAPE reactivities
 *  @param default_value    Result used for position with invalid/missing reactivity values
 */
int
vrna_sc_SHAPE_to_pr(const char  *shape_conversion,
                    double      *values,
                    int         length,
                    double      default_value);


#ifndef VRNA_DISABLE_BACKWARD_COMPATIBILITY

DEPRECATED(double **
           vrna_probing_data_load_n_distribute(unsigned int n_seq,
                                               unsigned int *ns,
                                               const char **sequences,
                                               const char **file_names,
                                               const int *file_name_association,
                                               unsigned int options),
           "This function is obsolete and will be removed in the future");


DEPRECATED(vrna_probing_data_t
           vrna_probing_data_Deigan2009(const double  *reactivities,
                                        unsigned int  n,
                                        double        m,
                                        double        b),
           "Use vrna_probing_data_deigan() instead");


DEPRECATED(vrna_probing_data_t
           vrna_probing_data_Deigan2009_comparative(const double        **reactivities,
                                                    const unsigned int  *n,
                                                    unsigned int        n_seq,
                                                    double              *ms,
                                                    double              *bs,
                                                    unsigned int        multi_params),
           "Use vrna_probing_data_deigan_comparative() instead");


DEPRECATED(vrna_probing_data_t
           vrna_probing_data_Zarringhalam2012(const double  *reactivities,
                                              unsigned int  n,
                                              double        beta,
                                              const char    *pr_conversion,
                                              double        pr_default),
           "Use vrna_probing_data_zarringhalam() instead");


DEPRECATED(vrna_probing_data_t
           vrna_probing_data_Zarringhalam2012_comparative(const double  **reactivities,
                                                          unsigned int  *n,
                                                          unsigned int  n_seq,
                                                          double        *betas,
                                                          const char    **pr_conversions,
                                                          double        *pr_defaults,
                                                          unsigned int  multi_params),
           "Use vrna_probing_data_zarringhalam_comparative() instead");


DEPRECATED(vrna_probing_data_t
           vrna_probing_data_Eddy2014_2(const double  *reactivities,
                                        unsigned int  n,
                                        const double  *unpaired_data,
                                        unsigned int  unpaired_len,
                                        const double  *paired_data,
                                        unsigned int  paired_len),
           "Use vrna_probing_data_eddy() instead");


DEPRECATED(vrna_probing_data_t
           vrna_probing_data_Eddy2014_2_comparative(const double  **reactivities,
                                                    unsigned int  *n,
                                                    unsigned int  n_seq,
                                                    const double  **unpaired_datas,
                                                    unsigned int  *unpaired_lens,
                                                    const double  **paired_datas,
                                                    unsigned int  *paired_lens,
                                                    unsigned int  multi_params),
           "Use vrna_probing_data_eddy_comparative() instead");


#endif


/**
 *  @}
 */

#endif
