//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Device/IO/ReadWriteINT.cpp
//! @brief     Implements functions read|writeBAInt
//!
//! @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 "Device/IO/ReadWriteINT.h"
#include "Base/Axis/Scale.h"
#include "Base/Util/StringUtil.h"
#include "Device/Data/ArrayUtil.h"
#include "Device/Data/Datafield.h"
#include "Device/IO/ParseUtil.h"

void writeDatafieldDoubles(const std::vector<double>& dataValues, std::ostream& output_stream,
                           size_t n_columns)
{
    output_stream.imbue(std::locale::classic());
    output_stream << std::scientific << std::setprecision(12);
    size_t ncol = 0;
    for (size_t i = 0; i < dataValues.size(); ++i) {
        ncol++;
        output_stream << Util::Parse::ignoreDenormalized(dataValues[i]) << "    ";
        if (ncol == n_columns) {
            output_stream << std::endl;
            ncol = 0;
        }
    }
}

Datafield* Util::RW::readBAInt(std::istream& input_stream)
{
    std::string line;

    std::vector<const Scale*> axes;
    while (std::getline(input_stream, line)) {
        line = Base::String::trim(line);

        if (line.find("axis") != std::string::npos)
            axes.emplace_back(Util::Parse::parseScale(input_stream));

        if (line.find("data") != std::string::npos)
            break;
    }
    // std::cout << "Read " << axes.size() << " axes" << std::endl;
    auto* result = new Datafield(std::move(axes));
    Util::Parse::fillDatafield(result, input_stream);
    return result;
}

void Util::RW::writeBAInt(const Datafield& data, std::ostream& output_stream)
{
    output_stream << "# BornAgain Intensity Data\n\n";

    for (size_t i = 0; i < data.rank(); ++i) {
        std::string axis_name = std::string("axis") + std::to_string(i);
        std::unique_ptr<Scale> axis(data.axis(i).clone());
        axis->setAxisName(axis_name);
        output_stream << std::endl;
        output_stream << "# axis-" << i << "\n";
        output_stream << (*axis) << "\n";
    }
    size_t n_columns = data.axis(data.rank() - 1).size();

    output_stream << "\n# data\n";
    writeDatafieldDoubles(data.flatVector(), output_stream, n_columns);

    if (data.hasErrorSigmas()) {
        output_stream << "\n\n# errorbars\n";
        writeDatafieldDoubles(data.errorSigmas(), output_stream, n_columns);
    }
    output_stream << std::endl;
}
