#ifndef _STENCIL_H
#define _STENCIL_H

#include <vector>
#include <memory>
#include <user/stimFrame.h>
#include <mentalEntity.h>

namespace smo {
namespace cologex {

/**
 * Stencil represents range descriptions for sub-regions of sensor data frames.
 *
 * When a sensor yields frames with multiple values per frame, the Stencil class
 * allows the stimbufflib driver to describe the subset of the input data that
 * is relevant to SMO. For example:
 *
 * * A HSB format camera might treat brightness values above 128 as
 *   negtrins, creating a Stencil that denotes all offsets in a
 *   frame that exceed 128.
 *
 * * A lidar yielding XYZI[ntensity] might consider I values exceeding 128 to be
 *   negtrins, creating a Stencil listing all values in the point
 *   cloud that exceed 128.
 *
 * The Stencil internally represents offsets with ranges or other efficient
 * formats to describe offsets (e.g., by row). The internal format is opaque to
 * the stimbufflib, which describes relevant ranges by calling Stencil methods.
 */
class Stencil
{
public:
	/**
	 * Constructor that takes a shared_ptr to StimFrame and produces a completed
	 * Stencil. The Stencil scans the StimFrame and efficiently allocates
	 * internal structures to describe the stencil ranges.
	 *
	 * @param frame Shared pointer to the StimFrame to analyze
	 * @param threshold The threshold value for determining relevant data
	 */
	Stencil(
		const std::shared_ptr<stim_buff::StimFrame> &frame,
		const uint32_t threshold)
	: frame(frame), threshold(threshold)
	{}
	virtual ~Stencil() = default;

	/**
	 * Pure virtual method for derived classes to implement their specific
	 * threshold analysis logic. Returns true if there are values above threshold,
	 * false otherwise.
	 */
	virtual bool analyzeFrame() = 0;

	/**
	 * Stencil is constructed from a StimFrame. If the input StimFrame had no
	 * values above threshold, then the Stencil will have no data.
	 */
	virtual bool hasData() const = 0;
	operator bool() const { return hasData(); }
	bool operator!() const { return !hasData(); }

	// Return the number of relevant ranges/offsets in this Stencil.
	virtual size_t getRelevantCount() const = 0;
	// Return true if the offset is relevant, false otherwise
	virtual bool isRelevant(size_t offset) const = 0;

	/**
	 * Build internal stencil metadata from the shared_ptr member to describe
	 * the range of StimFrame values that are relevant.
	 */
	virtual bool buildStencilMetadata() = 0;

protected:
	uint32_t threshold;
	std::shared_ptr<stim_buff::StimFrame> frame;
};

} // namespace cologex
} // namespace smo

#endif // _STENCIL_H
