//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Device/Histo/SimulationResult.cpp
//! @brief     Implements class SimulationResult.
//!
//! @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/Histo/SimulationResult.h"
#include "Base/Axis/Scale.h"
#include "Base/Util/Assert.h"
#include "Device/Coord/ICoordSystem.h"

SimulationResult::SimulationResult() = default;

SimulationResult::SimulationResult(const Datafield& data, const ICoordSystem* coords)
    : Datafield(coords, data.flatVector(), data.errorSigmas())
{
    ASSERT(coords);
    ASSERT(data.rank() == coords->rank());
}

SimulationResult::SimulationResult(const SimulationResult& other)
    : Datafield(other.converter().clone(), other.flatVector(), other.errorSigmas())
    , m_title(other.m_title)
{
}

SimulationResult::SimulationResult(SimulationResult&& other) noexcept = default;

SimulationResult::~SimulationResult() = default;

SimulationResult& SimulationResult::operator=(SimulationResult&& other) noexcept = default;

Datafield SimulationResult::extracted_field() const
{
    return Datafield(converter().convertedAxes(Coords::UNDEFINED), flatVector());
}

std::pair<double, double> SimulationResult::axisMinMax(size_t i, Coords units) const
{
    return {converter().calculateMin(i, units), converter().calculateMax(i, units)};
}

std::string SimulationResult::name_of_axis(size_t i, Coords units) const
{
    return converter().nameOfAxis(i, units);
}

const ICoordSystem& SimulationResult::converter() const
{
    const auto* coordsys = dynamic_cast<const ICoordSystem*>(m_frame.get());
    ASSERT(coordsys);
    return *coordsys;
}

#ifdef BORNAGAIN_PYTHON
PyObject* SimulationResult::array(Coords units) const
{
    Datafield data(converter().convertedAxes(units), flatVector());
    return data.npArray();
}
#endif

std::vector<double> SimulationResult::convertedBinCenters(Coords units) const
{
    return convertedBinCenters(0, units);
}

std::vector<double> SimulationResult::convertedBinCenters(size_t i_axis, Coords units) const
{
    ASSERT(i_axis < converter().rank());
    auto* axis = converter().convertedAxis(i_axis, units); // TODO memory leak
    return axis->binCenters();
}

void SimulationResult::setTitle(const std::string& title)
{
    m_title = title;
}
std::string SimulationResult::title()
{
    return m_title;
}
