#pragma once

#include "../../../../include/dv-processing/cluster/mean_shift/event_store_adaptor.hpp"

#include <pybind11/pybind11.h>

namespace py = pybind11;

/**
 * @brief Bind cluster::mean_shift::MeanShiftEventStoreAdaptor class to python
 * @param m pybind The module to bind to
 */
void bind_mean_shift_store_adaptor(py::module &m) {
	using pybind11::operator""_a;

	py::class_<dv::cluster::mean_shift::MeanShiftEventStoreAdaptor>(m, "MeanShiftEventStoreAdaptor",
		"This class implements the Mean Shift clustering algorithm with an Epanechnikov Kernel for event store data.")
		.def(py::init<const dv::EventStore &, const int16_t, float, const uint32_t,
				 const std::vector<dv::TimedKeyPoint, Eigen::aligned_allocator<dv::TimedKeyPoint>> &, const uint32_t>(),
			"events"_a, "bw"_a, "conv"_a, "maxIter"_a, "startingPoints"_a, "numLeaves"_a = 32768)
		.def(py::init<const dv::EventStore &, const int16_t, float, const uint32_t, const uint32_t, const uint32_t>(),
			"events"_a, "bw"_a, "conv"_a, "maxIter"_a, "numStartingPoints"_a, "numLeaves"_a = 32768)
		.def_static("generateStartingPointsFromData",
			&dv::cluster::mean_shift::MeanShiftEventStoreAdaptor::generateStartingPointsFromData,
			py::arg("numStartingPoints"), py::arg("events"),
			"Generates a vector of vectors containing the starting points by randomly selecting from provided data")
		.def_static("generateStartingPointsFromRange",
			&dv::cluster::mean_shift::MeanShiftEventStoreAdaptor::generateStartingPointsFromRange,
			py::arg("numStartingPoints"), py::arg("ranges"),
			"Generates a vector of vectors containing the starting points by generating random points within a given "
			"range for each dimension")
		.def("fit",
			&dv::cluster::mean_shift::MeanShiftEventStoreAdaptor::fit<dv::cluster::mean_shift::kernel::Epanechnikov>,
			"Executes the algorithm with an Epanechnikov algorithm.")
		.def("findClusterCentresEpanechnikov",
			&dv::cluster::mean_shift::MeanShiftEventStoreAdaptor::findClusterCentres<
				dv::cluster::mean_shift::kernel::Epanechnikov>,
			"Performs the search using the Epanechnikov kernel for the cluster centres for each given starting point. "
			"A detected centre is added to the set of centres if it isn't closer than the bandwidth to any previously "
			"detected centre..")
		.def("findClusterCentresGaussian",
			&dv::cluster::mean_shift::MeanShiftEventStoreAdaptor::findClusterCentres<
				dv::cluster::mean_shift::kernel::Gaussian>,
			"Performs the search using the Gaussian kernel for the cluster centres for each given starting point. A "
			"detected centre is added to the set of centres if it isn't closer than the bandwidth to any previously "
			"detected centre..")
		.def("fitGaussian",
			&dv::cluster::mean_shift::MeanShiftEventStoreAdaptor::fit<dv::cluster::mean_shift::kernel::Gaussian>,
			"Executes the algorithm with a Gaussian kernel.");
}
