//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      PyCore/Sample/ImportMultiLayer.h
//! @brief     Implements createMultiLayerFromPython.
//!
//! @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)
//
//  ************************************************************************************************

#ifdef BORNAGAIN_PYTHON

#include "PyCore/Sample/ImportMultiLayer.h"
#include "PyCore/Embed/PyCore.h"
#include "PyCore/Embed/PyInterpreter.h" // BornAgain::importScript
#include "auto/Wrap/swig_runtime.h"     // for creating a core object from Python
#include <stdexcept>

void* PyInterpreter::pyscript2object(const std::string& script, const std::string& functionName,
                                     const std::string& typeName, const std::string& path)
{
    PyObjectPtr tmpModule{PyInterpreter::BornAgain::importScript(script, path)};

    // locate the `get_simulation` function (it is an attribute of the module)
    PyObject* pAddFn = PyObject_GetAttrString(tmpModule.get(), functionName.c_str());
    if (!pAddFn)
        throw std::runtime_error(errorDescription("PyInterpreter::BornAgain: "
                                                  "Cannot locate the compiled function '"
                                                  + functionName + "'"));

    // create a `MultiLayer` Python object via calling the function
    PyObject* ret1 = PyObject_CallFunctionObjArgs(pAddFn, NULL);

    // clean up
    Py_DecRef(pAddFn);

    if (!ret1)
        throw std::runtime_error(
            errorDescription("Failed execting Python function '" + functionName + "'"));

    // Construct a C++ object from the Python object.
    // This conversion requires a SWIG-produced Python API.

    void* argp1 = 0;
    swig_type_info* pTypeInfo = SWIG_TypeQuery((typeName + "*").c_str());

    const int res = SWIG_ConvertPtr(ret1, &argp1, pTypeInfo, 0);
    if (!SWIG_IsOK(res)) {
        Py_DecRef(ret1);
        throw std::runtime_error(
            errorDescription("Function " + functionName + " did not yield MultiLayer instance"));
    }

    return reinterpret_cast<void*>(argp1);
}

#endif // BORNAGAIN_PYTHON
