#ifndef _STENCIL_H
#define _STENCIL_H

#include <cstddef>
#include <cstdint>
#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 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.
 *
 * * A lidar that extracts ambience might consider ambience counts below a
 *	 threshold to be postrins -- i.e, it incentivizes the agent to prefer
 *	 darker environments.
 *
 * 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:
	/**	EXPLANATION:
	 * This is used by smo and stimbufflibs to describe the range of bodyspot
	 * descriptors in a stencil. Each descriptor describes a contiguous range of
	 * body spots whose values exceed the intrin threshold for the intrin being
	 * reported. Or in the case of a stored cologex/idea, it describes
	 * contiguous body spots in the perceptual reference data, which may
	 * eventually be whittled/collapsed down from implicative data into
	 * structural data.
	 */
	struct RangeDescriptor
	{
		uint32_t stimulusBufferSpot;
		size_t nContiguousSpots;
	};

	Stencil() = default;
	virtual ~Stencil() = default;

	// Non-copyable, non-movable (stencils are constructed in place)
	Stencil(const Stencil&) = delete;
	Stencil& operator=(const Stencil&) = delete;
	Stencil(Stencil&&) = delete;
	Stencil& operator=(Stencil&&) = delete;

	/**
	 * Returns true if the Stencil has data, false otherwise.
	 */
	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;

	virtual size_t getNRangeDescriptors() const = 0;

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

} // namespace cologex
} // namespace smo

#endif // _STENCIL_H
