//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Base/Py/ArrayWrapper.h
//! @brief     Defines ArrayWrapper classes. The array descriptors are required to pass
//!            the type and size information of a C-Array to Python.
//!
//! @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)
//
//  ************************************************************************************************

#ifndef BORNAGAIN_BASE_PY_ARRAYWRAPPER_H
#define BORNAGAIN_BASE_PY_ARRAYWRAPPER_H

#ifdef BORNAGAIN_PYTHON

#include <vector>

//! Descriptor of a C-array to be passed to Python to construct a Numpy array.
class Arrayf64Wrapper {

public:
    Arrayf64Wrapper(const std::size_t rank, const int* dims, const std::vector<double>* array_ptr,
                    const bool copy_data);

    //-- methods required by SWIG --
    Arrayf64Wrapper() {};

    ~Arrayf64Wrapper() {};

    Arrayf64Wrapper(const Arrayf64Wrapper& other) { *this = other; }

    Arrayf64Wrapper& operator=(const Arrayf64Wrapper& other)
    {
        m_dims = other.m_dims;
        if (other.m_array_ptr) {
            m_array_ptr = other.m_array_ptr;
        } else {
            m_array_ptr = nullptr;
            m_array = other.m_array;
        }
        return *this;
    }
    //----------------------------------------

    //! Total size of the array.
    std::size_t size() const { return m_array_ptr ? m_array_ptr->size() : m_array.size(); }

    //! Returns the rank (= number of dimensions) of the array.
    std::size_t rank() const { return m_dims.size(); }

    //! Raw pointer to the array which stores the size of the underlying C-Array on each dimension.
    const std::vector<int>& dimensions() const { return m_dims; }

    //! Reference to the underlying array.
    const std::vector<double>& array() const
    {
        if (m_array_ptr)
            return *m_array_ptr;

        return m_array;
    }

    //! Returns true if the array owns its data.
    bool ownData() const { return m_array_ptr; }

private:
    std::vector<int> m_dims;     //!< Dimensions of the arrary (use int to be compatible to SWIG)
    std::vector<double> m_array; //!< Container for array values, used when data is owned
    const std::vector<double>* m_array_ptr = nullptr; //!< Raw pointer to the array data
};

#endif // BORNAGAIN_PYTHON

#endif // BORNAGAIN_BASE_PY_ARRAYWRAPPER_H
