/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/

#include "core_utils.h"

#include <ImageComponent.h>
#include <MeshComponent.h>

namespace py = pybind11;

namespace pybind11::detail {

// --------------- ComponentList ---------------
// Conversion from Python PyObject to C++ ComponentList
bool type_caster<camitk::ComponentList>::load(handle src, bool /* not used : indicates whether implicit conversions should be applied */) {
    // Accept list or tuple
    if (!py::isinstance<py::sequence>(src)) {
        return false;
    }
    py::sequence seq = reinterpret_borrow<py::sequence>(src);
    value.clear();
    for (auto comp : seq) {
        if (comp.is_none()) {
            value.append(nullptr);
        }
        else {
            camitk::Component* ptr = nullptr;

            // Try casting to camitk::Component
            try {
                ptr = comp.cast<camitk::Component*>();
            }
            catch (const py::cast_error&) {
                return false;  // Invalid item in list
            }

            value.append(ptr);
        }
    }

    return true;
}


// Conversion from C++ ComponentList to Python PyObject
handle type_caster<camitk::ComponentList>::cast(const camitk::ComponentList& list, return_value_policy /* policy */, handle /* parent */) {
    py::list pyList;

    for (camitk::Component* c : list) {
        // Dynamic cast must be used here as, for instance, the fact that VtkImageComponent inherits from ImageComponent
        // is not known/declared to pybind, which cannot cast properly and therefore remove the polymorphism in python
        // and from python get_image_data won't work
        camitk::ImageComponent* img = dynamic_cast<camitk::ImageComponent*>(c);
        if (img != nullptr) {
            pyList.append(py::cast(img, py::return_value_policy::reference));
        }
        else {
            camitk::MeshComponent* msh = dynamic_cast<camitk::MeshComponent*>(c);
            if (msh != nullptr) {
                pyList.append(py::cast(msh, py::return_value_policy::reference));
            }
            else {
                // py::return_value_policy::take_ownership is needed to ensure that pybind11 infers polymorphic return types correctly (Component, ImageComponent, MeshComponent...)
                pyList.append(py::cast(c, py::return_value_policy::reference));  // <- this will do the dynamic cast
            }
        }
    }

    return pyList.release();
}

} // namespace pybind11::detail

