#ifndef _USER_COMPARATOR_API_DESC_H
#define _USER_COMPARATOR_API_DESC_H

#include <functional>
#include <memory>
#include <string>
#include <vector>
#include <preprocessor.h>
#include <user/comparator.h>

namespace smo {

namespace stim_buff {
struct SmoCallbacks;
}

namespace cologex {

class ExportedComparatorTypeDesc
{
public:
	typedef std::function<std::unique_ptr<Comparator>()> GetNewInstanceFn;

	static bool sanityCheck(const ExportedComparatorTypeDesc &desc)
	{
		if (desc.name.empty()) { return false; }

		if (desc.typeId.vendorId == 0u && desc.typeId.typeId == 0u)
			{ return false; }

		if (!desc.getNewInstance) { return false; }
		return true;
	}

	std::string stringify() const
	{
		return name + " (" + typeId.stringify() + ")";
	}

public:
	std::string name;
	ComparatorTypeId typeId;
	GetNewInstanceFn getNewInstance;
};

class ComparatorLibDesc
{
public:
	static bool sanityCheck(const ComparatorLibDesc &desc)
	{
		if (desc.name.empty()) { return false; }
		if (desc.exportedComparatorTypes.empty()) { return false; }

		for (const auto& exportedType : desc.exportedComparatorTypes)
		{
			if (!ExportedComparatorTypeDesc::sanityCheck(exportedType)) {
				return false;
			}
		}

		return true;
	}

	std::string stringify() const
	{
		std::string result = "Name: " + name + "\n";
		result += "Exported Comparator Types:\n";
		for (size_t i = 0; i < exportedComparatorTypes.size(); ++i)
		{
			result += "  - " + exportedComparatorTypes[i].stringify();
			if (i + 1 < exportedComparatorTypes.size()) {
				result += "\n";
			}
		}
		return result;
	}

public:
	std::string name;
	std::vector<ExportedComparatorTypeDesc> exportedComparatorTypes;
};

} // namespace cologex

#define SMO_GET_COMPARATOR_LIB_DESC_FN_NAME getComparatorLibDesc
#define SMO_GET_COMPARATOR_LIB_DESC_FN_NAME_STR \
	SMO_QUOTE(SMO_GET_COMPARATOR_LIB_DESC_FN_NAME)
#define SMO_GET_COMPARATOR_LIB_DESC_FN_TYPEDEF \
	SMO_CONCAT(SMO_GET_COMPARATOR_LIB_DESC_FN_NAME, Fn)

typedef const cologex::ComparatorLibDesc& (SMO_GET_COMPARATOR_LIB_DESC_FN_TYPEDEF)(
	const stim_buff::SmoCallbacks& callbacks);

} // namespace smo

#endif // _USER_COMPARATOR_API_DESC_H
