//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sample/Correlation/PeakShape.h
//! @brief     Defines the interface PeakShape and subclasses.
//!
//! @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)
//
//  ************************************************************************************************

#ifndef BORNAGAIN_SAMPLE_CORRELATION_IPEAKSHAPE_H
#define BORNAGAIN_SAMPLE_CORRELATION_IPEAKSHAPE_H

#include "Base/Type/Cloneable.h"
#include <heinz/Vectors3D.h>

//! Abstract base class class that defines the peak shape of a Bragg peak.

class PeakShape : public Cloneable {
public:
    PeakShape() = default;

    virtual ~PeakShape() = default;

#ifndef SWIG
    PeakShape* clone() const override = 0;

    //! Peak shape at q from a reciprocal lattice point at q_lattice_point
    virtual double peakDistribution(const R3& q, const R3& q_lattice_point) const = 0;

    //! Indicates if the peak shape encodes angular disorder, in which case all peaks in a
    //! spherical shell are needed
    virtual bool angularDisorder() const { return false; }
#endif // SWIG
};

//! Class that implements an isotropic Gaussian peak shape of a Bragg peak.

class IsotropicGaussPeakShape : public PeakShape {
public:
    IsotropicGaussPeakShape(double max_intensity, double domainsize);
    ~IsotropicGaussPeakShape() override;

#ifndef SWIG
    IsotropicGaussPeakShape* clone() const override;

    double peakDistribution(const R3& q, const R3& q_lattice_point) const override;

private:
    double peakDistribution(const R3& q) const;
    double m_max_intensity;
    double m_domainsize;
#endif // SWIG
};

//! An isotropic Lorentzian peak shape of a Bragg peak.

class IsotropicLorentzPeakShape : public PeakShape {
public:
    IsotropicLorentzPeakShape(double max_intensity, double domainsize);
    ~IsotropicLorentzPeakShape() override;

#ifndef SWIG
    IsotropicLorentzPeakShape* clone() const override;

    double peakDistribution(const R3& q, const R3& q_lattice_point) const override;

private:
    double peakDistribution(const R3& q) const;
    double m_max_intensity;
    double m_domainsize;
#endif // SWIG
};

//! A peak shape that is Gaussian in the radial direction and
//! uses the Mises-Fisher distribution in the angular direction.

class GaussFisherPeakShape : public PeakShape {
public:
    GaussFisherPeakShape(double max_intensity, double radial_size, double kappa);
    ~GaussFisherPeakShape() override;

#ifndef SWIG
    GaussFisherPeakShape* clone() const override;

    double peakDistribution(const R3& q, const R3& q_lattice_point) const override;

    bool angularDisorder() const override { return true; }

private:
    double m_max_intensity;
    double m_radial_size;
    double m_kappa;
#endif // SWIG
};

//! A peak shape that is Lorentzian in the radial direction and uses the
//! Mises-Fisher distribution in the angular direction.

class LorentzFisherPeakShape : public PeakShape {
public:
    LorentzFisherPeakShape(double max_intensity, double radial_size, double kappa);
    ~LorentzFisherPeakShape() override;

#ifndef SWIG
    LorentzFisherPeakShape* clone() const override;

    double peakDistribution(const R3& q, const R3& q_lattice_point) const override;

    bool angularDisorder() const override { return true; }

private:
    double m_max_intensity;
    double m_radial_size;
    double m_kappa;
#endif // SWIG
};

//! A peak shape that is Gaussian in the radial direction and a convolution of a
//! Mises-Fisher distribution with a Mises distribution on the two-sphere.

class MisesFisherGaussPeakShape : public PeakShape {
public:
    MisesFisherGaussPeakShape(double max_intensity, double radial_size, const R3& zenith,
                              double kappa_1, double kappa_2);
    ~MisesFisherGaussPeakShape() override;

#ifndef SWIG
    MisesFisherGaussPeakShape* clone() const override;

    double peakDistribution(const R3& q, const R3& q_lattice_point) const override;

    bool angularDisorder() const override { return true; }

private:
    double m_max_intensity;
    double m_radial_size;
    R3 m_zenith;
    double m_kappa_1, m_kappa_2;
#endif // SWIG
};

//! A peak shape that is a convolution of a Mises-Fisher distribution with a 3d Gaussian.

class MisesGaussPeakShape : public PeakShape {
public:
    MisesGaussPeakShape(double max_intensity, double radial_size, const R3& zenith, double kappa);
    ~MisesGaussPeakShape() override;

#ifndef SWIG
    MisesGaussPeakShape* clone() const override;

    double peakDistribution(const R3& q, const R3& q_lattice_point) const override;

    bool angularDisorder() const override { return true; }

private:
    double m_max_intensity;
    double m_radial_size;
    R3 m_zenith;
    double m_kappa;
#endif // SWIG
};

#endif // BORNAGAIN_SAMPLE_CORRELATION_IPEAKSHAPE_H
