//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sim/Scan/PhysicalScan.h
//! @brief     Declares interface PhysicalScan.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2023
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#ifndef BORNAGAIN_SIM_SCAN_PHYSICALSCAN_H
#define BORNAGAIN_SIM_SCAN_PHYSICALSCAN_H

#include "Sim/Scan/BeamScan.h"
#include <memory>

class Distribution1D;
class Footprint;
struct ParameterSample;

//! Abstract base class for alpha and lambda scans.

class PhysicalScan : public BeamScan {
public:
    PhysicalScan(const Scale& axis);
    ~PhysicalScan() override;

    void setWavelength(double lambda);
    //! Distribution with absolute width, **complementing** wavelength values
    void setWavelengthDistribution(const Distribution1D& distr);

    void setGrazingAngle(double alpha);
    //! Distribution with absolute width, **complementing** grazing angle values
    void setGrazingAngleDistribution(const Distribution1D& distr);

    void setAzimuthalAngle(double phi);
    //! Distribution with absolute width, **complementing** azimuthal angle values
    void setAzimuthalAngleDistribution(const Distribution1D& distr);

    void setFootprint(const Footprint* footprint);

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

    const Footprint* commonFootprint() const;
    const Footprint* footprintAt(size_t i) const;

    double commonWavelength() const;
    double wavelengthAt(size_t i) const;

    double commonGrazingAngle() const;
    double grazingAngleAt(size_t i) const;

    double commonAzimuthalAngle() const;
    double azimuthalAngleAt(size_t i) const;

    // needed for export
    const Distribution1D* wavelengthDistribution() const { return m_lambda_distrib.get(); }
    const Distribution1D* grazingAngleDistribution() const { return m_alpha_distrib.get(); }
    const Distribution1D* azimuthalAngleDistribution() const { return m_phi_distrib.get(); }
    size_t nDistributionSamples() const override;

protected:
    void copyPhysicalScan(PhysicalScan* dest) const; //!< Used by subclass::clone

    std::unique_ptr<Distribution1D> m_lambda_distrib;
    std::unique_ptr<Distribution1D> m_alpha_distrib;
    std::unique_ptr<Distribution1D> m_phi_distrib;

private:
    bool isCommonFootprint() const;
    bool isCommonWavelength() const;
    bool isCommonGrazingAngle() const;
    bool isCommonAzimuthalAngle() const;

#endif // SWIG
};

#endif // BORNAGAIN_SIM_SCAN_PHYSICALSCAN_H
