//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/Model/Util/UtilXML.cpp
//! @brief     Implements
//!
//! @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/Util/UtilXML.h"
#include "Base/Util/Assert.h"

namespace {

void assertCurrentTag(QXmlStreamReader* reader, const QString& expectedTag)
{

    if (reader->name() != expectedTag)
        throw std::runtime_error("Found tag '" + reader->name().toString().toStdString()
                                 + "' instead of expected expected tag '"
                                 + expectedTag.toStdString() + "'");
}

void assertCurrentToken(QXmlStreamReader* reader, QXmlStreamReader::TokenType token)
{
    if (reader->tokenType() != token)
        throw std::runtime_error("Found unexpected token type");
}

} // namespace


void XML::gotoEndElementOfTag(QXmlStreamReader* reader, const QString& tag)
{
    ASSERT(reader);
    if (reader->name() != tag) {
        if (!reader->isEndElement())
            reader->skipCurrentElement();
        reader->skipCurrentElement();
    }
    assertCurrentTag(reader, tag);
    if (!reader->isEndElement())
        reader->skipCurrentElement();

    assertCurrentToken(reader, QXmlStreamReader::EndElement);
    assertCurrentTag(reader, tag);
}

// ------------ write atribute ------------

void XML::writeAttribute(QXmlStreamWriter* writer, const QString& attributeName, bool b)
{
    writer->writeAttribute(attributeName, b ? "1" : "0");
}

void XML::writeAttribute(QXmlStreamWriter* writer, const QString& attributeName, double d)
{
    writer->writeAttribute(attributeName, d == 0.0 ? "0" : QString::number(d, 'e', 12));
}

void XML::writeAttribute(QXmlStreamWriter* writer, const QString& attributeName, QString s)
{
    writer->writeAttribute(attributeName, s);
}

void XML::writeAttribute(QXmlStreamWriter* writer, const QString& attributeName, QColor c)
{
    writer->writeAttribute(attributeName, c.isValid() ? c.name(QColor::HexArgb) : "");
}


// ------------ read atribute ------------

bool XML::readBool(QXmlStreamReader* reader, const QString& attributeName)
{
    return reader->attributes().value(attributeName).toUInt() > 0;
}

int XML::readInt(QXmlStreamReader* reader, const QString& attributeName)
{
    return reader->attributes().value(attributeName).toInt();
}

unsigned XML::readUInt(QXmlStreamReader* reader, const QString& attributeName)
{
    return reader->attributes().value(attributeName).toUInt();
}

double XML::readDouble(QXmlStreamReader* reader, const QString& attributeName)
{
    return reader->attributes().value(attributeName).toDouble();
}

QString XML::readString(QXmlStreamReader* reader, const QString& attributeName)
{
    return reader->attributes().value(attributeName).toString();
}

bool XML::readTaggedBool(QXmlStreamReader* reader, const QString& tag)
{
    bool result = XML::readBool(reader, XML::Attrib::value);
    XML::gotoEndElementOfTag(reader, tag);
    return result;
}
int XML::readTaggedInt(QXmlStreamReader* reader, const QString& tag)
{
    int result = XML::readInt(reader, XML::Attrib::value);
    XML::gotoEndElementOfTag(reader, tag);
    return result;
}
unsigned XML::readTaggedUInt(QXmlStreamReader* reader, const QString& tag)
{
    unsigned result = XML::readUInt(reader, XML::Attrib::value);
    XML::gotoEndElementOfTag(reader, tag);
    return result;
}
double XML::readTaggedDouble(QXmlStreamReader* reader, const QString& tag)
{
    double result = XML::readDouble(reader, XML::Attrib::value);
    XML::gotoEndElementOfTag(reader, tag);
    return result;
}
QString XML::readTaggedString(QXmlStreamReader* reader, const QString& tag)
{
    QString result = XML::readString(reader, XML::Attrib::value);
    XML::gotoEndElementOfTag(reader, tag);
    return result;
}
QColor XML::readTaggedColor(QXmlStreamReader* reader, const QString& tag)
{
    const QString s = readTaggedString(reader, tag);
    XML::gotoEndElementOfTag(reader, tag);
    return {s};
}
