//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Base/Math/IntegratorCollection.h
//! @brief     Defines Integrator classes.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#ifdef SWIG
#error no need to expose this header to Swig
#endif // SWIG
#ifndef BORNAGAIN_BASE_MATH_INTEGRATORCOLLECTION_H
#define BORNAGAIN_BASE_MATH_INTEGRATORCOLLECTION_H

#include <functional>
#include <gsl/gsl_integration.h>

//! Base class for integrators from GNU Scientific Library.
class Integrator {
public:
    virtual ~Integrator() = default;

protected:
    Integrator();
    static double m_Cfunction(double x, void* p)
    {
        return (*(const std::function<double(double)>*)(p))(x);
    };
    gsl_function m_gsl_f;
};


//! Adaptive integrator QAG from GNU Scientific Library.
//! https://www.gnu.org/software/gsl/doc/html/integration.html#qag-adaptive-integration
class GKAdaptiveIntegrator : public Integrator {
public:
    GKAdaptiveIntegrator(size_t max_subintervals);
    ~GKAdaptiveIntegrator();
    double integrate(const std::function<double(double)>& f, double lmin, double lmax,
                     double epsabs, double epsrel, int key, size_t limit);

    size_t max_subintervals;

private:
    gsl_integration_workspace* m_workspace;
};


//! Non-adaptive integrator QNG from GNU Scientific Library.
//! https://www.gnu.org/software/gsl/doc/html/integration.html#qng-non-adaptive-gauss-kronrod-integration
class GKIntegrator : public Integrator {
public:
    GKIntegrator();
    ~GKIntegrator() = default;
    double integrate(const std::function<double(double)>& f, double lmin, double lmax,
                     double epsabs, double epsrel);
};


//! Romberg integrator from GNU Scientific Library.
//! https://www.gnu.org/software/gsl/doc/html/integration.html#romberg-integration
class RombergIntegrator : public Integrator {
public:
    RombergIntegrator(size_t subdivision_depth);
    ~RombergIntegrator();
    double integrate(const std::function<double(double)>& f, double lmin, double lmax,
                     double epsabs, double epsrel);

private:
    gsl_integration_romberg_workspace* m_romberg_workspace;
};

#endif // BORNAGAIN_BASE_MATH_INTEGRATORCOLLECTION_H
