//
// Created by marcel on 21.11.23.
//

#ifndef PYFICTION_RANDOM_SIDB_LAYOUT_GENERATOR_HPP
#define PYFICTION_RANDOM_SIDB_LAYOUT_GENERATOR_HPP

#include "pyfiction/documentation.hpp"
#include "pyfiction/types.hpp"

#include <fiction/algorithms/simulation/sidb/random_sidb_layout_generator.hpp>

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

namespace pyfiction
{

namespace detail
{

template <typename Lyt>
void random_sidb_layout_generator(pybind11::module& m)
{
    namespace py = pybind11;
    using namespace pybind11::literals;

    py::enum_<typename fiction::generate_random_sidb_layout_params<Lyt>::positive_charges>(
        m, "positive_charges", DOC(fiction_generate_random_sidb_layout_params_positive_charges))
        .value("ON", fiction::generate_random_sidb_layout_params<Lyt>::positive_charges::ALLOWED)
        .value("OFF", fiction::generate_random_sidb_layout_params<Lyt>::positive_charges::FORBIDDEN)

        ;

    /**
     * Parameters.
     */
    py::class_<fiction::generate_random_sidb_layout_params<Lyt>>(m, "generate_random_sidb_layout_params",
                                                                 DOC(fiction_generate_random_sidb_layout_params))
        .def(py::init<>())
        .def_readwrite("coordinate_pair", &fiction::generate_random_sidb_layout_params<Lyt>::coordinate_pair,
                       DOC(fiction_generate_random_sidb_layout_params_coordinate_pair))
        .def_readwrite("number_of_sidbs", &fiction::generate_random_sidb_layout_params<Lyt>::number_of_sidbs,
                       DOC(fiction_generate_random_sidb_layout_params_number_of_sidbs))
        .def_readwrite("positive_sidbs", &fiction::generate_random_sidb_layout_params<Lyt>::positive_sidbs,
                       DOC(fiction_generate_random_sidb_layout_params_positive_sidbs))
        .def_readwrite("minimal_spacing", &fiction::generate_random_sidb_layout_params<Lyt>::minimal_spacing,
                       DOC(fiction_generate_random_sidb_layout_params_minimal_spacing))
        .def_readwrite("maximal_attempts", &fiction::generate_random_sidb_layout_params<Lyt>::maximal_attempts,
                       DOC(fiction_generate_random_sidb_layout_params_maximal_attempts))
        .def_readwrite("number_of_unique_generated_layouts",
                       &fiction::generate_random_sidb_layout_params<Lyt>::number_of_unique_generated_layouts,
                       DOC(fiction_generate_random_sidb_layout_params_number_of_unique_generated_layouts))
        .def_readwrite("maximal_attempts_for_multiple_layouts",
                       &fiction::generate_random_sidb_layout_params<Lyt>::maximal_attempts_for_multiple_layouts,
                       DOC(fiction_generate_random_sidb_layout_params_maximal_attempts_for_multiple_layouts))

        ;

    m.def("generate_random_sidb_layout", &fiction::generate_random_sidb_layout<Lyt>, "lyt_skeleton"_a,
          "params"_a = fiction::generate_random_sidb_layout_params<Lyt>{}, DOC(fiction_generate_random_sidb_layout));

    m.def("generate_multiple_random_sidb_layouts", &fiction::generate_multiple_random_sidb_layouts<Lyt>,
          "lyt_skeleton"_a, "params"_a = fiction::generate_random_sidb_layout_params<Lyt>{},
          DOC(fiction_generate_multiple_random_sidb_layouts));
}

}  // namespace detail

inline void random_sidb_layout_generator(pybind11::module& m)
{
    // NOTE be careful with the order of the following calls! Python will resolve the first matching overload!

    detail::random_sidb_layout_generator<py_charge_distribution_surface>(m);
}

}  // namespace pyfiction

#endif  // PYFICTION_RANDOM_SIDB_LAYOUT_GENERATOR_HPP
