//  ************************************************************************************************
//
//  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
{
    XML::writeAttribute(w, XML::Attrib::version, uint(1));
    m_lattice_rotation_angle.writeTo(w, Tag::LatticeRotationAngle);
}

void Lattice2DItem::readFrom(QXmlStreamReader* r)
{
    const uint version = XML::readUIntAttribute(r, XML::Attrib::version);
    Q_UNUSED(version)

    while (r->readNextStartElement()) {
        QString tag = r->name().toString();

        if (tag == Tag::LatticeRotationAngle)
            m_lattice_rotation_angle.readFrom(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.value(), m_length2.value(),
                                            Units::deg2rad(m_angle.value()),
                                            Units::deg2rad(m_lattice_rotation_angle.value()));
}

void BasicLattice2DItem::writeTo(QXmlStreamWriter* w) const
{
    XML::writeAttribute(w, XML::Attrib::version, uint(1));

    // parameters from base class
    w->writeStartElement(Tag::BaseData);
    Lattice2DItem::writeTo(w);
    w->writeEndElement();

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

void BasicLattice2DItem::readFrom(QXmlStreamReader* r)
{
    const uint version = XML::readUIntAttribute(r, XML::Attrib::version);
    Q_UNUSED(version)

    while (r->readNextStartElement()) {
        QString tag = r->name().toString();

        // parameters from base class
        if (tag == Tag::BaseData) {
            Lattice2DItem::readFrom(r);
            XML::gotoEndElementOfTag(r, tag);

        } else if (tag == Tag::Length1)
            m_length1.readFrom(r, tag);
        else if (tag == Tag::Length2)
            m_length2.readFrom(r, tag);
        else if (tag == Tag::Angle)
            m_angle.readFrom(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,
                                             Units::deg2rad(m_lattice_rotation_angle.value()));
}

void SquareLattice2DItem::writeTo(QXmlStreamWriter* w) const
{
    XML::writeAttribute(w, XML::Attrib::version, uint(1));

    // parameters from base class
    w->writeStartElement(Tag::BaseData);
    Lattice2DItem::writeTo(w);
    w->writeEndElement();

    // length
    w->writeStartElement(Tag::Length);
    m_length.writeTo(w);
    w->writeEndElement();
}

void SquareLattice2DItem::readFrom(QXmlStreamReader* r)
{
    const uint version = XML::readUIntAttribute(r, XML::Attrib::version);
    Q_UNUSED(version)

    while (r->readNextStartElement()) {
        QString tag = r->name().toString();

        // parameters from base class
        if (tag == Tag::BaseData) {
            Lattice2DItem::readFrom(r);
            XML::gotoEndElementOfTag(r, tag);

            // length
        } else if (tag == Tag::Length) {
            m_length.readFrom(r);
            XML::gotoEndElementOfTag(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.value(),
                                                Units::deg2rad(m_lattice_rotation_angle.value()));
}

void HexagonalLattice2DItem::writeTo(QXmlStreamWriter* w) const
{
    XML::writeAttribute(w, XML::Attrib::version, uint(1));

    // parameters from base class
    w->writeStartElement(Tag::BaseData);
    Lattice2DItem::writeTo(w);
    w->writeEndElement();

    // length
    w->writeStartElement(Tag::Length);
    m_length.writeTo(w);
    w->writeEndElement();
}

void HexagonalLattice2DItem::readFrom(QXmlStreamReader* r)
{
    const uint version = XML::readUIntAttribute(r, XML::Attrib::version);
    Q_UNUSED(version)

    while (r->readNextStartElement()) {
        QString tag = r->name().toString();

        // parameters from base class
        if (tag == Tag::BaseData) {
            Lattice2DItem::readFrom(r);
            XML::gotoEndElementOfTag(r, tag);

            // length
        } else if (tag == Tag::Length) {
            m_length.readFrom(r);
            XML::gotoEndElementOfTag(r, tag);

        } else
            r->skipCurrentElement();
    }
}
