#pragma once

#include "../../../include/dv-processing/noise/frequency_filters.hpp"

#include <pybind11/pybind11.h>

namespace py = pybind11;

/**
 * @brief Binds frequency noise filters to python.
 * @param m The module to bind to.
 */
void bind_frequency_filters(py::module &m) {
	py::class_<dv::noise::LowPassFilter<>, std::shared_ptr<dv::noise::LowPassFilter<>>>(m, "LowPassFilter",
		"Low-pass filter discards events if their temporal frequency at a given pixel location is above the cutoff "
		"frequency. This is also commonly referred to as refractory period filtering, where the refractory period is "
		"the "
		"inverse of the cutoff frequency. This is useful for removing high frequency noise from events "
		"(cutoff frequency in the range of a few kHz).")
		.def(py::init<const cv::Size &, const float>(), py::arg("resolution"), py::arg("cutOffFrequency"))
		.def("accept", &dv::noise::LowPassFilter<>::accept, py::arg("events"), "Accepts incoming events.")
		.def("generateEvents", &dv::noise::LowPassFilter<>::generateEvents,
			"Apply the filter algorithm and return only the filtered events from the ones that were accepted as input.")
		.def("retain", &dv::noise::LowPassFilter<>::retain, "Test whether event should be kept or discarded.")
		.def("getNumberOfIncomingEvents", &dv::noise::LowPassFilter<>::getNumberOfIncomingEvents,
			"Get number of total events that were accepted by the noise filter.")
		.def("getNumberOfOutgoingEvents", &dv::noise::LowPassFilter<>::getNumberOfOutgoingEvents,
			"Total number of outgoing events from this filter instance.")
		.def("getReductionFactor", &dv::noise::LowPassFilter<>::getReductionFactor,
			"Get the reduction factor of this filter. It's a fraction representation of events that were discard by "
			"this filter compared to the amount of incoming events.")
		.def("getCutOffFrequency", &dv::noise::LowPassFilter<>::getCutOffFrequency, "Get the cutoff frequency.")
		.def("setCutOffFrequency", &dv::noise::LowPassFilter<>::setCutOffFrequency, py::arg("frequency"),
			"Set a new cutoff frequency.");

	py::class_<dv::noise::HighPassFilter<>, std::shared_ptr<dv::noise::HighPassFilter<>>>(m, "HighPassFilter",
		"High-pass filter discards events if their temporal frequency at a given pixel location is below the cutoff "
		"frequency. This is useful for removing low frequency hot pixels (cutoff frequency in the range of a few Hz to "
		"a few hundred Hz).")
		.def(py::init<const cv::Size &, const float>(), py::arg("resolution"), py::arg("cutOffFrequency"))
		.def("accept", &dv::noise::HighPassFilter<>::accept, py::arg("events"), "Accepts incoming events.")
		.def("generateEvents", &dv::noise::HighPassFilter<>::generateEvents,
			"Apply the filter algorithm and return only the filtered events from the ones that were accepted as input.")
		.def("retain", &dv::noise::HighPassFilter<>::retain, "Test whether event should be kept or discarded.")
		.def("getNumberOfIncomingEvents", &dv::noise::HighPassFilter<>::getNumberOfIncomingEvents,
			"Get number of total events that were accepted by the noise filter.")
		.def("getNumberOfOutgoingEvents", &dv::noise::HighPassFilter<>::getNumberOfOutgoingEvents,
			"Total number of outgoing events from this filter instance.")
		.def("getReductionFactor", &dv::noise::HighPassFilter<>::getReductionFactor,
			"Get the reduction factor of this filter. It's a fraction representation of events that were discard by "
			"this filter compared to the amount of incoming events.")
		.def("getCutOffFrequency", &dv::noise::HighPassFilter<>::getCutOffFrequency, "Get the cutoff frequency.")
		.def("setCutOffFrequency", &dv::noise::HighPassFilter<>::setCutOffFrequency, py::arg("frequency"),
			"Set a new cutoff frequency.");

	py::class_<dv::noise::BandPassFilter<>, std::shared_ptr<dv::noise::BandPassFilter<>>>(m, "BandPassFilter",
		"Band-pass filter discards events if their temporal frequency at a given pixel location is outside of a "
		"frequency"
		"band defined by a lower and upper cutoff frequency. Note that this is a combination of a LowPassFilter "
		"and a HighPassFilter combined together for ease of use/performance. This is useful for only capturing events "
		"within a given frequency range defined by the lower and upper cutoff frequencies.")
		.def(py::init<const cv::Size &, const float, const float>(), py::arg("resolution"),
			py::arg("lowerCutOffFrequency"), py::arg("upperCutOffFrequency"))
		.def("accept", &dv::noise::BandPassFilter<>::accept, py::arg("events"), "Accepts incoming events.")
		.def("generateEvents", &dv::noise::BandPassFilter<>::generateEvents,
			"Apply the filter algorithm and return only the filtered events from the ones that were accepted as input.")
		.def("retain", &dv::noise::BandPassFilter<>::retain, "Test whether event should be kept or discarded.")
		.def("getNumberOfIncomingEvents", &dv::noise::BandPassFilter<>::getNumberOfIncomingEvents,
			"Get number of total events that were accepted by the noise filter.")
		.def("getNumberOfOutgoingEvents", &dv::noise::BandPassFilter<>::getNumberOfOutgoingEvents,
			"Total number of outgoing events from this filter instance.")
		.def("getReductionFactor", &dv::noise::BandPassFilter<>::getReductionFactor,
			"Get the reduction factor of this filter. It's a fraction representation of events that were discard by "
			"this filter compared to the amount of incoming events.")
		.def("getLowerCutOffFrequency", &dv::noise::BandPassFilter<>::getLowerCutOffFrequency,
			"Get the lower "
			"cutoff frequency.")
		.def("getUpperCutOffFrequency", &dv::noise::BandPassFilter<>::getUpperCutOffFrequency,
			"Get the upper "
			"cutoff frequency.")
		.def("setLowerCutOffFrequency", &dv::noise::BandPassFilter<>::setLowerCutOffFrequency, py::arg("frequency"),
			"Set a new lower cutoff frequency.")
		.def("setUpperCutOffFrequency", &dv::noise::BandPassFilter<>::setUpperCutOffFrequency, py::arg("frequency"),
			"Set a new upper cutoff frequency.");

	py::class_<dv::noise::BandCutFilter<>, std::shared_ptr<dv::noise::BandCutFilter<>>>(m, "BandCutFilter",
		"Band-cut filter discards events if their temporal frequency at a given pixel location is inside of a frequency"
		"band defined by a lower and upper cutoff frequency. Note that this is a combination of a LowPassFilter "
		"and a HighPassFilter combined together for ease of use/performance. This is useful for discarding events "
		"within a given frequency range defined by the lower and upper cutoff frequencies.")
		.def(py::init<const cv::Size &, const float, const float>(), py::arg("resolution"),
			py::arg("lowerCutOffFrequency"), py::arg("upperCutOffFrequency"))
		.def("accept", &dv::noise::BandCutFilter<>::accept, py::arg("events"), "Accepts incoming events.")
		.def("generateEvents", &dv::noise::BandCutFilter<>::generateEvents,
			"Apply the filter algorithm and return only the filtered events from the ones that were accepted as input.")
		.def("retain", &dv::noise::BandCutFilter<>::retain, "Test whether event should be kept or discarded.")
		.def("getNumberOfIncomingEvents", &dv::noise::BandCutFilter<>::getNumberOfIncomingEvents,
			"Get number of total events that were accepted by the noise filter.")
		.def("getNumberOfOutgoingEvents", &dv::noise::BandCutFilter<>::getNumberOfOutgoingEvents,
			"Total number of outgoing events from this filter instance.")
		.def("getReductionFactor", &dv::noise::BandCutFilter<>::getReductionFactor,
			"Get the reduction factor of this filter. It's a fraction representation of events that were discard by "
			"this filter compared to the amount of incoming events.")
		.def("getLowerCutOffFrequency", &dv::noise::BandCutFilter<>::getLowerCutOffFrequency,
			"Get the lower "
			"cutoff frequency.")
		.def("getUpperCutOffFrequency", &dv::noise::BandCutFilter<>::getUpperCutOffFrequency,
			"Get the upper "
			"cutoff frequency.")
		.def("setLowerCutOffFrequency", &dv::noise::BandCutFilter<>::setLowerCutOffFrequency, py::arg("frequency"),
			"Set a new lower cutoff frequency.")
		.def("setUpperCutOffFrequency", &dv::noise::BandCutFilter<>::setUpperCutOffFrequency, py::arg("frequency"),
			"Set a new upper cutoff frequency.");
}
