#pragma once

#include "FSDKError.h"
#include "IHumanDetectionBatch.h"
#include "IObject.h"
#include "Types/Human.h"

namespace fsdk {

#ifndef DOXYGEN_SHOULD_SKIP_THIS
	DECLARE_SMARTPTR(IHumanDetector);
#endif

/**
 * @defgroup DetectorGroup Human detector.
 * @brief Human detector public interfaces and related types and structures.
 * @{
 * */

	/**
	 * @brief Human detection type enumeration.
	 * */
	enum HumanDetectionType {
		HDT_BOX    = 0,     //!< Get bounding boxes of human bodies.
		HDT_POINTS = 1<<0,  //!< Get 17 keypoints of human, with score for each one.
		HDT_ALL    = 0xffff //!< Get all supported parameters.
	};

	inline HumanDetectionType operator | (HumanDetectionType a, HumanDetectionType b) { 
		return static_cast<HumanDetectionType>(static_cast<int>(a) | static_cast<int>(b));
	}

	/**
	 * @brief human body detector interface.
	 * */
	struct IHumanDetector : IRefCounted {
		/**
		 * @brief Batched detect of human bodies.
		 * @param [in] images span of source images.
		 * @param [in] rects span of input rectangles of interest.
		 * @param [in] detectionPerImageNum max number of detections per input image.
		 * @param [in] type Human detection type.
		 * @return ResultValue with error code and IHumanDetectionBatch object.
		 * @see Ref, Span, Image, Rect, IHumanDetectionBatch, HumanDetectionType, ResultValue and FSDKError for details.
		 * @note images format must be R8G8B8, @see Format.
		 * @note all spans should be based on user owned continuous collections.
		 * @note all spans should be equal size.
		 */
		virtual ResultValue<FSDKError, Ref<IHumanDetectionBatch>>
		detect(
			Span<const Image> images,
			Span<const Rect> rects,
			uint32_t detectionPerImageNum,
			HumanDetectionType type = HDT_BOX) const noexcept = 0;

		/**
		 * @brief Detect one person on input image.
		 * @param [in] image source image.
		 * @param [in] rect rectangle of interest in the image.
		 * @param [in] type Human detection type.
		 * @return ResultValue with ErrorCode and Human (invalid - if detection not found).
		 * @see Image, Rect, Human, HumanDetectionType, ResultValue and FSDKError for details.
		 * @note image format must be R8G8B8, @see Format.
		 */
		virtual ResultValue<FSDKError, Human>
		detectOne(
			const Image& image,
			const Rect& rect,
			HumanDetectionType type = HDT_BOX) const noexcept = 0;

		/**
		 * @brief redetect one person from input image.
		 * @param [in] image source image.
		 * @param [in] detection span of detection coordinates in corresponding source images space to make a redetect.
		 * @param [in] type Human detection type.
		 * @return ResultValue with ErrorCode and Human (invalid - if detection not found).
		 * @see Image, Detection, Human, HumanDetectionType, ResultValue and FSDKError for details.
		 * @note image format must be R8G8B8, @see Format.
		 **/
		virtual ResultValue<FSDKError, Human>
		redetectOne(
			const Image& image,
			const Detection& detection,
			HumanDetectionType type = HDT_BOX) const noexcept = 0;

		/**
		 * @brief Batched redetect humans on multiple images
		 * based on the detection results for the previous frames.
		 * @param [in] images span of source images.
		 * @param [in] detectionBatch result of detection on the previous frames - 
		 * Ref with an IHumanDetectionBatch object.
		 * @param [in] type type of redetection.
		 * @return ResultValue with error code and IHumanDetectionBatch object.
		 * @see Ref, Span, Image, IHumanDetectionBatch, HumanDetectionType, ResultValue and FSDKError for details.
		 * @note images format must be R8G8B8, @see Format.
		 * @note all spans should be based on user owned continuous collections.
		 * @note images span should be the same size with detectionBatch size.
		 * @note In case if some human from the input detectionBatch was not found
		 * the corresponding detection in the output IHumanDetectionBatch object
		 * will be invalid.
		 */
		virtual ResultValue<FSDKError, IHumanDetectionBatchPtr>
		redetect(
			Span<const Image> images,
			Ref<IHumanDetectionBatch> detectionBatch,
			HumanDetectionType type = HDT_BOX) const noexcept = 0;

		/**
		 * @brief Batched redetect humans on multiple images
		 * based on the detection results for the previous frames.
		 * @param [in] images span of source images.
		 * @param [in] detections span of detection coordinates in corresponding source images space
		 * from the previous frames. It is a two dimensional Span. There is one Span of the rectangles for each image.
		 * @param [in] type type of redetection.
		 * @return ResultValue with error code and IHumanDetectionBatch object.
		 * @see Span, Image, Detection, IHumanDetectionBatch, HumanDetectionType, ResultValue and FSDKError for details.
		 * @note images format must be R8G8B8, @see Format.
		 * @note all spans should be based on user owned continuous collections.
		 * @note all spans should be equal size.
		 * @note If for some of the input detections the redetected human will not be found the 
		 * appropriate detection in the IHumanDetectionBatch object will be invalid.
		 */
		virtual ResultValue<FSDKError, IHumanDetectionBatchPtr>
		redetect(
			Span<const Image> images,
			Span<Span<const Detection>> detections,
			HumanDetectionType type = HDT_BOX) const noexcept = 0;

		/**
		 * @brief Validate input of multiple frames in a single function call.
		 * @param [in] images span of source images.
		 * @param [in] rects span of rectangle coordinates of corresponding source images.
		 * @param [in] detectionPerImageNum max number of detections per input image.
		 * @param [out] errors output span of errors for each image.
		 * @return Result with error code.
		 * @see Span, Image, Rect, Result and FSDKError for details.
		 * @note images format must be R8G8B8, @see Format.
		 * @note all spans should be based on user owned continuous collections.
		 * @note all spans should be equal size.
		 * */
		virtual Result<FSDKError>
		validate(
			Span<const Image> images,
			Span<const Rect> rects,
			uint32_t detectionPerImageNum,
			Span<Result<FSDKError>> errors) const noexcept = 0;

		/**	
		 * @brief Validate input of multiple frames in a single function call.
		 * @param [in] images span of source images.
		 * @param [in] detectionBatch result of detection on the previous frames - 
		 * Ref with an IHumanDetectionBatch object.
		 * @param [out] errors output span of errors for each image.
		 * @return Result with error code.
		 * @see Ref, Span, Image, IHumanDetectionBatch, Result and FSDKError for details.
		 * @note images format must be R8G8B8, @see Format.
		 * @note all spans should be based on user owned continuous collections.
		 * @note all spans should be equal size.
		 * */
		virtual Result<FSDKError> validate(
			Span<const Image> images,
			Ref<IHumanDetectionBatch> detectionBatch,
			Span<Result<FSDKError>> errors) const noexcept = 0;

		/**
		 * @brief Validate input of multiple frames in a single function call.
		 * @param [in] images span of source images.
		 * @param [in] detections span of detection coordinates in corresponding source images space
		 * from the previous frames. It is a two dimensional Span. There is one Span of the Detections for each image.
		 * @param [out] errors output span of errors for each image.
		 *  It is a two dimensional Span. There is one Span of the errors for each image.
		 * @return Result with error code.
		 * @see Span, Image, Detection, Result and FSDKError for details.
		 * @note images format must be R8G8B8, @see Format.
		 * @note all spans should be based on user owned continuous collections.
		 * @note all spans should be equal size.
		 * */
		virtual Result<FSDKError>
		validate(
			Span<const Image> images,
			Span<Span<const Detection>> detections,
			Span<Span<Result<FSDKError>>> errors) const noexcept = 0;

	};

/** @} */

}