//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sample/Multilayer/Layer.h
//! @brief     Defines class Layer.
//!
//! @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_MULTILAYER_LAYER_H
#define BORNAGAIN_SAMPLE_MULTILAYER_LAYER_H

#include "Sample/Multilayer/ILayer.h"
#include "Sample/Multilayer/PlainLayer.h"
#include <memory>
#include <vector>

class IParticle;
class Material;
class Slice;
class Struct2D;
class Struct3D;
class Struct;

//! A layer in a multilayer Sample.

class Layer : public PlainLayer, public ILayer {
public:
    Layer(const Material& material, double thickness, const Roughness* roughness = nullptr);
    Layer(const Material& material, const Roughness* roughness = nullptr);
    ~Layer() override;

#ifndef SWIG
    Layer(const Layer& other);
    Layer(Layer&& other) noexcept(false);
#endif
    // 2D structures:
    // - deposited on bottom interface (ReferencePlane::BottomOfLayer)
    void deposit2D(const Struct2D& structure);
    void addDeposit2D(double coverage, const Struct2D& structure);
    // - suspended below top interface (ReferencePlane::TopOfLayer)
    void suspend2D(const Struct2D& structure);
    void addSuspend2D(double coverage, const Struct2D& structure);

    // 3D structures (filling layer volume):
    void fill3D(const Struct3D& structure);
    void add3D(double coverage, const Struct3D& structure);

    void setNumberOfSlices(unsigned int n_slices);

#ifndef SWIG
    std::vector<std::unique_ptr<Layer>> flatClones() const override;
    unsigned int numberOfSlices() const { return m_n_slices; }

    //! Returns 2D structures at layer bottom (from deposit2D).
    const std::vector<std::unique_ptr<Struct2D>>& structsAtBottom() const
    {
        return m_structsAtBottom;
    }
    //! Returns 2D structures at layer top (from suspend2D).
    const std::vector<std::unique_ptr<Struct2D>>& structsAtTop() const { return m_structsAtTop; }
    //! Returns 3D structures (from fill3D/add3D).
    const std::vector<std::unique_ptr<Struct3D>>& structs3D() const { return m_structs3D; }

    Layer* clone() const override;

protected:
    Layer(const Material& material, const Span& span, const Roughness* roughness = nullptr);

private:
    std::vector<std::unique_ptr<Struct2D>> m_structsAtBottom; //!< 2D structures at bottom interface
    std::vector<std::unique_ptr<Struct2D>> m_structsAtTop;    //!< 2D structures at top interface
    std::vector<std::unique_ptr<Struct3D>> m_structs3D;       //!< 3D structures filling volume
    unsigned int m_n_slices{1}; //!< Requested number of slices per particle-containing span

#endif // SWIG
};

#endif // BORNAGAIN_SAMPLE_MULTILAYER_LAYER_H
