//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sample/Lattice/Lattice2D.h
//! @brief     Defines classes of Lattice2D family.
//!
//! @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_LATTICE_LATTICE2D_H
#define BORNAGAIN_SAMPLE_LATTICE_LATTICE2D_H

#include "Base/Type/Cloneable.h"

//! A two-dimensional Bravais lattice.
struct ReciprocalBases {
    double m_asx, m_asy; //!< x,y coordinates of a*
    double m_bsx, m_bsy; //!< x,y coordinates of b*
};

class Lattice2D : public Cloneable {
public:
    explicit Lattice2D(double xi);

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

    virtual double length1() const = 0;
    virtual double length2() const = 0;
    virtual double latticeAngle() const = 0;
    virtual double unitCellArea() const = 0;

    double rotationAngle() const { return m_xi; }

    ReciprocalBases reciprocalBases() const;

    void setRotationEnabled(bool enabled);

    virtual void validate() const {}

protected:
    mutable bool m_validated{false};
    double m_xi;
#endif // SWIG
};

//! A two-dimensional Bravais lattice with no special symmetry.

class BasicLattice2D : public Lattice2D {
public:
    BasicLattice2D(double length1, double length2, double angle, double xi);

#ifndef SWIG
    BasicLattice2D* clone() const override;
    void validate() const override;

    double length1() const override { return m_length1; }
    double length2() const override { return m_length2; }
    double latticeAngle() const override { return m_angle; }
    double unitCellArea() const override;

private:
    double m_length1, m_length2;
    double m_angle;
#endif // SWIG
};

//! A two-dimensional Bravais lattice with square unit cell.

class SquareLattice2D : public Lattice2D {
public:
    SquareLattice2D(double length, double xi = 0.0);

#ifndef SWIG
    SquareLattice2D* clone() const override;
    void validate() const override;

    double length1() const override { return m_length; }
    double length2() const override { return m_length; }
    double latticeAngle() const override;
    double unitCellArea() const override;

private:
    double m_length;
#endif // SWIG
};

//! A two-dimensional Bravais lattice with hexagonal symmetry.

class HexagonalLattice2D : public Lattice2D {
public:
    HexagonalLattice2D(double length, double xi);

#ifndef SWIG
    HexagonalLattice2D* clone() const override;
    void validate() const override;

    double length1() const override { return m_length; }
    double length2() const override { return m_length; }
    double latticeAngle() const override;
    double unitCellArea() const override;

private:
    double m_length;
#endif // SWIG
};

#endif // BORNAGAIN_SAMPLE_LATTICE_LATTICE2D_H
