#ifndef _USER_COMPARATOR_H
#define _USER_COMPARATOR_H

#include <cstdint>
#include <memory>
#include <sstream>
#include <string>
#include <mentalEntity.h>
#include <user/logic.h>

namespace smo {
namespace cologex {

constexpr uint32_t SMO_COMPARATOR_VENDOR_ID = 0x511110FFu;
constexpr uint32_t SMO_COMPARATOR_TYPE_BODY_SPOT = 0x51100001u;
constexpr uint32_t SMO_COMPARATOR_TYPE_STIM_FEAT = 0x51100002u;
constexpr uint32_t SMO_COMPARATOR_TYPE_SIMULTANEITY_STAMP = 0x51100003u;

/** Disk-stable comparator type identity: vendorId + typeId (64 bits packed). */
struct ComparatorTypeId
{
	uint32_t vendorId;
	uint32_t typeId;

	constexpr uint64_t pack() const
	{
		return (static_cast<uint64_t>(vendorId) << 32)
			| static_cast<uint64_t>(typeId);
	}

	static constexpr ComparatorTypeId unpack(uint64_t packed)
	{
		return ComparatorTypeId{
			static_cast<uint32_t>(packed >> 32),
			static_cast<uint32_t>(packed)
		};
	}

	constexpr bool operator==(const ComparatorTypeId& other) const
	{
		return vendorId == other.vendorId && typeId == other.typeId;
	}

	constexpr bool operator!=(const ComparatorTypeId& other) const
	{
		return !(*this == other);
	}

	std::string stringify() const
	{
		std::ostringstream result;
		result << std::hex << std::showbase;
		result << "vendorId=" << vendorId << " typeId=" << typeId;
		return result.str();
	}
};

class Comparator
:	public MentalEntity, public logic::Operand
{
public:
	explicit Comparator(MentalEntity::Id id)
	:	MentalEntity(id)
	{}

	virtual ~Comparator() = default;

	virtual ComparatorTypeId getTypeId() const = 0;

	/**		EXPLANATION:
	 * The reference for a Comparator is the fixed mentity or range of mentities
	 * that this comparator is intended to validate a match against.
	 */
	std::shared_ptr<MentalEntity> reference;
};

class ComparatorExpression
:	public logic::UnaryExpression
{
public:
	ComparatorExpression(
		logic::Operator &op, std::shared_ptr<Comparator> &comparator
	)
	:	logic::UnaryExpression(
			op, std::static_pointer_cast<logic::Operand>(comparator))
	{}
};

} // namespace cologex
} // namespace smo

#endif // _USER_COMPARATOR_H
