#pragma once

#include "../../../../include/dv-processing/core/frame/accumulator.hpp"

#include <pybind11/pybind11.h>

namespace py = pybind11;

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

	py::class_<dv::Accumulator> accumulatorClass(m, "Accumulator");

	py::enum_<dv::Accumulator::Decay>(accumulatorClass, "Decay")
		.value("NONE", dv::Accumulator::Decay::NONE)
		.value("LINEAR", dv::Accumulator::Decay::LINEAR)
		.value("EXPONENTIAL", dv::Accumulator::Decay::EXPONENTIAL)
		.value("STEP", dv::Accumulator::Decay::STEP);

	accumulatorClass
		.def(py::init<const cv::Size &>(), py::arg("resolution"),
			"Default parameter constructors, applies reasonable default accumulation parameters (the same defaults as "
			"within dv-runtime module): Decay function: Exponential Decay param: 1.0e+6 Event contribution: 0.04 "
			"Minimum potential: 0.0 Neutral potential: 0.0 Maximum potential: 0.3 Synchronous decay: off Polarity "
			"rectification (all event regarded as positive): off")
		.def(py::init<const cv::Size &, dv::Accumulator::Decay, double, bool, float, float, float, float, bool>(),
			py::arg("resolution"), py::arg("decayFunction"), py::arg("decayParam"), py::arg("synchronousDecay"),
			py::arg("eventContribution"), py::arg("maxPotential"), py::arg("neutralPotential"), py::arg("minPotential"),
			py::arg("rectifyPolarity"),
			"Accumulator constructor Creates a new Accumulator with the given params. By selecting the params the "
			"right way, the Accumulator can be used for a multitude of applications. The class also provides static "
			"factory functions that adjust the parameters for common use cases.")
		.def(
			"accept",
			[](dv::Accumulator &self, const dv::EventStore &events) {
				self.accept(events);
			},
			py::arg("events"), "Add events to the accumulator")
		.def(
			"generateFrame",
			[](dv::Accumulator &self) -> dv::Frame {
				return self.generateFrame();
			},
			"Generates the accumulation frame (potential surface) at the time of the last consumed event. The function "
			"writes the output image into the given `image` argument. The output frame will contain data with type "
			"CV_8U.")
		.def("clear", &dv::Accumulator::clear,
			"Clears the potential surface by setting it to the neutral value. This function does not reset the time "
			"surface.")
		.def("setDecayFunction", &dv::Accumulator::setDecayFunction, py::arg("decayFunction"),
			"The decay function the module should use to perform the decay")
		.def("setDecayParam", &dv::Accumulator::setDecayParam, py::arg("decayParam"),
			"The decay param. This is slope for linear decay, tau for exponential decay")
		.def("setEventContribution", &dv::Accumulator::setEventContribution, py::arg("contribution"),
			"Contribution to the potential surface an event shall incur. This contribution is either counted "
			"positively (for positive events or when `rectifyPolarity` is set).")
		.def("setMinPotential", &dv::Accumulator::setMinPotential, py::arg("minPotential"),
			"Set the minimum potential at which the surface should be capped at.")
		.def("setMaxPotential", &dv::Accumulator::setMaxPotential, py::arg("maxPotential"),
			"Set the max potential at which the surface should be capped at.")
		.def("setNeutralPotential", &dv::Accumulator::setNeutralPotential, py::arg("neutralPotential"),
			"Set the neutral potential to which the decay function should go. Exponential decay always goes to 0. The "
			"parameter is ignored there.")
		.def("setIgnorePolarity", &dv::Accumulator::setIgnorePolarity, py::arg("ignorePolarity"),
			"If set to true, all events will incur a positive contribution to the potential surface.")
		.def("setSynchronousDecay", &dv::Accumulator::setSynchronousDecay, py::arg("synchronousDecay"),
			"If set to true, all valued get decayed to the frame generation time at frame generation. If set to false, "
			"the values only get decayed on activity.")
		.def("getDecayFunction", &dv::Accumulator::getDecayFunction)
		.def("getDecayParam", &dv::Accumulator::getDecayParam)
		.def("getEventContribution", &dv::Accumulator::getEventContribution)
		.def("getMinPotential", &dv::Accumulator::getMinPotential)
		.def("getMaxPotential", &dv::Accumulator::getMaxPotential)
		.def("getNeutralPotential", &dv::Accumulator::getNeutralPotential)
		.def("isIgnorePolarity", &dv::Accumulator::isIgnorePolarity, "Check whether polarity of events is ignored.")
		.def("getPotentialSurface", &dv::Accumulator::getPotentialSurface,
			"Retrieve a copy of the currently accumulated potential surface");
}
