#pragma once

#include "../../../include/dv-processing/core/event.hpp"
#include "../../../include/dv-processing/core/event_color.hpp"

#include <pybind11/pybind11.h>

namespace py = pybind11;

/**
 * @brief Binds the event functions to python.
 * @param m The module to bind to.
 */
void bind_event(py::module &m) {
	py::enum_<dv::EventColor>(m, "EventColor")
		.value("WHITE", dv::EventColor::WHITE)
		.value("RED", dv::EventColor::RED)
		.value("GREEN1", dv::EventColor::GREEN1)
		.value("BLUE", dv::EventColor::BLUE)
		.value("GREEN2", dv::EventColor::GREEN2);

	py::enum_<dv::PixelArrangement>(m, "PixelArrangement")
		.value("MONO", dv::PixelArrangement::MONO)
		.value("RGBG", dv::PixelArrangement::RGBG)
		.value("GRGB", dv::PixelArrangement::GRGB)
		.value("GBGR", dv::PixelArrangement::GBGR)
		.value("BGRG", dv::PixelArrangement::BGRG);

	m.def("colorForEvent", &dv::colorForEvent, py::arg("event"), py::arg("pixelArrangement"),
		"Determine the color of the Bayer color filter for a specific event, based on its address.");

	m.def("colorForPoint", &dv::colorForPoint, py::arg("pixelCoordinates"), py::arg("pixelArrangement"),
		"Determine the color of the Bayer color filter for specific pixel coordinates.");

	m.def("coordinateHash", &dv::coordinateHash, py::arg("x"), py::arg("y"),
		"Function that creates perfect hash for 2d coordinates.");

	m.def(
		"roiFilter",
		[](const dv::EventStore &events, const cv::Rect &roi) {
			dv::EventStore filtered;
			dv::roiFilter(events, filtered, roi);
			return filtered;
		},
		py::arg("events"), py::arg("roi"),
		"Extracts only the events that are within the defined region of interest. This function copies the events from "
		"the in EventStore into the given out EventStore, if they intersect with the given region of interest "
		"rectangle.");

	m.def(
		"polarityFilter",
		[](const dv::EventStore &events, const bool polarity) {
			dv::EventStore filtered;
			dv::polarityFilter(events, filtered, polarity);
			return filtered;
		},
		py::arg("events"), py::arg("polarity"),
		"Filters events by polarity. Only events that exhibit the same polarity as given in polarity are kept.");

	m.def(
		"maskFilter",
		[](const dv::EventStore &events, const cv::Mat &mask) {
			dv::EventStore filtered;
			dv::maskFilter(events, filtered, mask);
			return filtered;
		},
		py::arg("events"), py::arg("mask"),
		"Filter event with a coordinate mask. Discards any events that happen on coordinates where mask has a zero "
		"value and retains all events with coordinates where mask has a non-zero value.");

	m.def(
		"scale",
		[](const dv::EventStore &events, const double xDivision, const double yDivision) {
			dv::EventStore scaled;
			dv::scale(events, scaled, xDivision, yDivision);
			return scaled;
		},
		py::arg("events"), py::arg("xDivision"), py::arg("yDivision"),
		"Projects the event coordinates onto a smaller range. The x- and y-coordinates the divided by xFactor and "
		"yFactor respectively and floored to the next integer. This forms the new coordinates of the event. Due to the "
		"nature of this, it can happen that multiple events end up happening simultaneously at the same location. This "
		"is still a valid event stream, as time keeps monotonically increasing, but is something that is unlikely to "
		"be generated by an event camera.");

	m.def("boundingRect", &dv::boundingRect<dv::EventStore>, py::arg("events"),
		"Computes and returns a rectangle with dimensions such that all the events in the given `EventStore` fall into "
		"the bounding box.");
}
