//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/Model/Sample/Lattice2DItems.cpp
//! @brief     Implements classes Lattice2DItems.
//!
//! @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)
//
//  ************************************************************************************************

#include "GUI/Model/Sample/Lattice2DItems.h"
#include "Base/Const/Units.h"
#include "GUI/Model/Util/UtilXML.h"
#include "Sample/Lattice/Lattice2D.h"

namespace {
namespace Tag {

const QString LatticeRotationAngle("LatticeRotationAngle");
const QString Length("Length");
const QString Length1("Length1");
const QString Length2("Length2");
const QString Angle("Angle");
const QString BaseData("BaseData");

} // namespace Tag
} // namespace

Lattice2DItem::Lattice2DItem()
{
    m_lattice_rotation_angle.init(
        "Xi (deg)",
        "Rotation of lattice with respect to x-axis of reference frame (beam direction)", 0.0, 2,
        1.0, RealLimits::limited(0.0, 360.0), "xi");
}

void Lattice2DItem::writeTo(QXmlStreamWriter* w) const
{
    m_lattice_rotation_angle.writeTo2(w, Tag::LatticeRotationAngle);
}

void Lattice2DItem::readFrom(QXmlStreamReader* r)
{
    while (r->readNextStartElement()) {
        QString tag = r->name().toString();

        if (tag == Tag::LatticeRotationAngle)
            m_lattice_rotation_angle.readFrom2(r, tag);
        else
            r->skipCurrentElement();
    }
}

double Lattice2DItem::unitCellArea() const
{
    return createLattice()->unitCellArea();
}

// --------------------------------------------------------------------------------------------- //

BasicLattice2DItem::BasicLattice2DItem()
{
    m_length1.init("LatticeLength1 (nm)", "Length of first lattice vector", 20.0, "len1");
    m_length2.init("LatticeLength2 (nm)", "Length of second lattice vector", 20.0, "len2");
    m_angle.init("Angle (deg)", "Angle between lattice vectors", 90.0, 2, 1.0,
                 RealLimits::limited(0, 180.0), "angle");
}

std::unique_ptr<Lattice2D> BasicLattice2DItem::createLattice() const
{
    return std::make_unique<BasicLattice2D>(m_length1.dVal(), m_length2.dVal(),
                                            Units::deg2rad(m_angle.dVal()),
                                            Units::deg2rad(m_lattice_rotation_angle.dVal()));
}

void BasicLattice2DItem::writeTo(QXmlStreamWriter* w) const
{
    XML::writeBaseElement<Lattice2DItem>(w, XML::Tag::BaseData, this);

    m_length1.writeTo2(w, Tag::Length1);
    m_length2.writeTo2(w, Tag::Length2);
    m_angle.writeTo2(w, Tag::Angle);
}

void BasicLattice2DItem::readFrom(QXmlStreamReader* r)
{
    while (r->readNextStartElement()) {
        QString tag = r->name().toString();
        if (tag == Tag::BaseData)
            XML::readBaseElement<Lattice2DItem>(r, tag, this);

        else if (tag == Tag::Length1)
            m_length1.readFrom2(r, tag);
        else if (tag == Tag::Length2)
            m_length2.readFrom2(r, tag);
        else if (tag == Tag::Angle)
            m_angle.readFrom2(r, tag);
        else
            r->skipCurrentElement();
    }
}

// --------------------------------------------------------------------------------------------- //

SquareLattice2DItem::SquareLattice2DItem()
{
    m_length.init("LatticeLength (nm)", "Length of first and second lattice vectors", 20.0, "len");
}

std::unique_ptr<Lattice2D> SquareLattice2DItem::createLattice() const
{
    return std::make_unique<SquareLattice2D>(m_length.dVal(),
                                             Units::deg2rad(m_lattice_rotation_angle.dVal()));
}

void SquareLattice2DItem::writeTo(QXmlStreamWriter* w) const
{
    XML::writeBaseElement<Lattice2DItem>(w, XML::Tag::BaseData, this);

    // length
    m_length.writeTo2(w, Tag::Length);
}

void SquareLattice2DItem::readFrom(QXmlStreamReader* r)
{
    while (r->readNextStartElement()) {
        QString tag = r->name().toString();
        if (tag == Tag::BaseData)
            XML::readBaseElement<Lattice2DItem>(r, tag, this);
        else if (tag == Tag::Length) {
            m_length.readFrom2(r, tag);

        } else
            r->skipCurrentElement();
    }
}

// --------------------------------------------------------------------------------------------- //

HexagonalLattice2DItem::HexagonalLattice2DItem()
{
    m_length.init("LatticeLength (nm)", "Length of first and second lattice vectors", 20.0, "len");
}

std::unique_ptr<Lattice2D> HexagonalLattice2DItem::createLattice() const
{
    return std::make_unique<HexagonalLattice2D>(m_length.dVal(),
                                                Units::deg2rad(m_lattice_rotation_angle.dVal()));
}

void HexagonalLattice2DItem::writeTo(QXmlStreamWriter* w) const
{
    XML::writeBaseElement<Lattice2DItem>(w, XML::Tag::BaseData, this);

    // length
    m_length.writeTo2(w, Tag::Length);
}

void HexagonalLattice2DItem::readFrom(QXmlStreamReader* r)
{
    while (r->readNextStartElement()) {
        QString tag = r->name().toString();
        if (tag == Tag::BaseData)
            XML::readBaseElement<Lattice2DItem>(r, tag, this);
        else if (tag == Tag::Length) {
            m_length.readFrom2(r, tag);

        } else
            r->skipCurrentElement();
    }
}
