//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/coregui/DataLoaders/AutomaticDataLoader1D.cpp
//! @brief     Implements class AutomaticDataLoader1D
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2021
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "GUI/coregui/DataLoaders/AutomaticDataLoader1D.h"
#include "Device/Data/OutputData.h"
#include "Device/InputOutput/OutputDataReadReflectometry.h"
#include "GUI/coregui/DataLoaders/AutomaticDataLoader1DResultModel.h"
#include "GUI/coregui/Models/RealDataItem.h"
#include "GUI/coregui/Models/SpecularDataItem.h"
#include "GUI/coregui/utils/DeserializationException.h"
#include "GUI/coregui/utils/ImportDataInfo.h"
#include "qcustomplot.h"

QString AutomaticDataLoader1D::name() const
{
    return "Legacy from BornAgain 1.18";
}

QString AutomaticDataLoader1D::persistentClassName() const
{
    return "AutomaticDataLoader1D";
}

AbstractDataLoader* AutomaticDataLoader1D::clone() const
{
    auto loader = new AutomaticDataLoader1D();
    loader->deserialize(serialize());
    return loader;
}

QByteArray AutomaticDataLoader1D::serialize() const
{
    QByteArray a;
    QDataStream s(&a, QIODevice::WriteOnly);
    s.setVersion(QDataStream::Qt_5_12);

    s << (quint8)1; // version
    s << m_fileContent;
    s << m_error;

    return a;
}

void AutomaticDataLoader1D::deserialize(const QByteArray& data)
{
    m_fileContent.clear();
    m_error.clear();

    QDataStream s(data);
    s.setVersion(QDataStream::Qt_5_12);

    quint8 version;
    s >> version;

    if (version == 1) {
        s >> m_fileContent;
        s >> m_error;
    } else
        throw DeserializationException::tooNew();

    if (s.status() != QDataStream::Ok)
        throw DeserializationException::streamError();
}

void AutomaticDataLoader1D::setFileContents(const QByteArray& fileContent)
{
    m_fileContent = fileContent;
}

QByteArray AutomaticDataLoader1D::fileContent() const
{
    return m_fileContent;
}

void AutomaticDataLoader1D::processContents()
{
    ASSERT(m_item != nullptr);
    ASSERT(m_item->isSpecularData());

    try {
        std::stringstream str(m_fileContent.constData());
        auto oData = OutputDataReadReflectometry().readOutputData(str);

        ImportDataInfo importInfo(std::move(*oData), Axes::Units::QSPACE);
        m_item->setImportData(std::move(importInfo));
        m_error.clear();
    } catch (std::runtime_error& ex) {
        m_item->removeNativeData();
        m_item->specularDataItem()->setOutputData(nullptr);
        m_error = QString::fromStdString(ex.what());
        if (m_error.isEmpty())
            m_error = "Unspecified error";
    }

    emit contentsProcessed();
}

AbstractDataLoaderResultModel* AutomaticDataLoader1D::createResultModel() const
{
    return new AutomaticDataLoader1DResultModel(m_item);
}

int AutomaticDataLoader1D::numErrors() const
{
    return m_error.isEmpty() ? 0 : 1;
}

QStringList AutomaticDataLoader1D::lineUnrelatedErrors() const
{
    if (!m_error.isEmpty())
        return {m_error};

    return {};
}
