

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of CMSDK version 2.1.1.260726 (26 July 2026)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2026
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  and is released under the following
//_/_/  
//_/_/  EXTENDED BSD License
//_/_/
//_/_/  Redistribution and use in source and binary forms, with or without
//_/_/  modification, is permitted provided that the following conditions 
//_/_/  are met:
//_/_/
//_/_/  - Redistributions of source code must retain the above copyright 
//_/_/    and collaboration notice, this list of conditions and the following 
//_/_/    disclaimer.
//_/_/
//_/_/  - Redistributions in binary form must reproduce the above copyright 
//_/_/    notice, this list of conditions and the following disclaimer in the 
//_/_/    documentation and/or other materials provided with the distribution.
//_/_/
//_/_/  - Neither the name of its copyright holders nor the names of its 
//_/_/    contributors may be used to endorse or promote products derived from 
//_/_/    this software without specific prior written permission.
//_/_/
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license. The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
/*! @file Types.h
	@brief Core fixed-width scalar typedefs and the PsyType / PsyContext hierarchical identifiers.

	This file defines the CMSDK-wide, architecture-independent integer and
	floating point types (int8..int64, uint8..uint64, float32/float64) selected
	via the ARCH_32 / ARCH_64 build defines, plus the two central hierarchical
	identifier structs used throughout Psyclone: PsyType (message types) and
	PsyContext (execution contexts). Both structs are plain fixed-size PODs so
	they can be embedded directly in wire/shared-memory structures such as
	DataMessageHeader.

	PLATFORM DIFFERENCES: on 64-bit builds, Windows maps int64/uint64 to
	(unsigned) long long while other platforms use int64_t/uint64_t from
	&lt;cstdint&gt;; the sizes are identical, only the underlying compiler types (and
	hence printf format expectations) differ — which is also why the
	-Wformat warning is suppressed on non-Windows GCC builds.
	@ingroup Messaging
*/

#if !defined(__types_h)              // Sentry, use file only if it's not already included.
#define __types_h

#include "Standard.h"
#include <stdio.h>
#include <cstdint>
#include <string.h>
// #define CNSPORT 10000
// #define FACTORYPORT 10001

#define CNSPRIORITY 90
#define FACTORYPRIORITY 90

#define BITFREE 1
#define BITOCCUPIED 0

#ifdef WINDOWS
#else
#pragma GCC diagnostic ignored "-Wformat"
#endif

#if defined	ARCH_32

	typedef				bool		bit;
	typedef	signed		char		int8;
	typedef	unsigned	char		uint8;
	typedef				short		int16;
	typedef	unsigned	short		uint16;
	typedef				int			int32;
	typedef	unsigned	int			uint32;
	typedef				long long	int64;
	typedef	unsigned	long long	uint64;
	typedef				float		float32;
	typedef				double		float64;
//	typedef				uint32		paddr;

#elif defined	ARCH_64

	typedef				bool		bit;
	typedef	signed		char		int8;
	typedef	unsigned	char		uint8;
	typedef				short		int16;
	typedef	unsigned	short		uint16;
	typedef				int			int32;
	typedef	unsigned	int			uint32;
	typedef				float		float32;
	typedef				double		float64;
//	typedef				uint32		paddr;

	#ifdef WINDOWS
		typedef				long long	int64;
		typedef	unsigned	long long	uint64;
	#else
		typedef				int64_t		int64;
		typedef				uint64_t	uint64;
	#endif

#endif

#define INT32_NOVALUE		0x12345678
#define INT64_NOVALUE		0x123456789ABCDEF0L
#define FLOAT64_NOVALUE		0.123456789123456789

#define MAXVALUINT8    ((uint8)~((uint8)0))
#define MAXVALINT8     ((int8)(MAXVALUINT8 >> 1))
#define MAXVALUINT16   ((uint16)~((uint16)0))
#define MAXVALINT16    ((int16)(MAXVALUINT16 >> 1))
#define MAXVALUINT32   ((uint32)~((uint32)0))
#define MAXVALINT32    ((int32)(MAXVALUINT32 >> 1))
#define MAXVALUINT64   ((uint64)~((uint64)0))
#define MAXVALINT64    ((int64)(MAXVALUINT64 >> 1))

#define MERGEUINT3264(a,b)	(((uint64)a)<<32)|((uint64)b)
#define GET1UINT3264(a)		(uint32)((a & 0xffffffff00000000L)>>32)
#define GET2UINT3264(a)		(uint32)(a & 0x00000000ffffffffL)
#define MERGEUINT1632(a,b)	(((uint32)a)<<16)|((uint32)b)
#define GET1UINT1632(a)		(uint16)((a & 0xffff0000L)>>16)
#define GET2UINT1632(a)		(uint16)(a & 0x0000ffffL)

//! Number of hierarchy levels in a PsyType.
#define PSYTYPELEVELS 16

/*! @brief Hierarchical message type identifier — the key used for publish/subscribe matching in Psyclone.

	A PsyType is a fixed array of 16 uint16 levels forming a dotted hierarchy,
	e.g. "2.201.3" is stored as levels = {2, 201, 3, 0, ...}. Level value 0 ends
	the hierarchy (a valid type must have levels[0] != 0) and the special value
	0xFFFF acts as a wildcard in matches(). Subscriptions match message types
	via matches(), so a subscriber to "2.201.0xFFFF" receives all subtypes of
	"2.201".

	@code
	PsyType t;
	t.fromString("2.201.3");     // parse dotted notation
	std::string s = t.toString(); // "2.201.3"
	if (t.matches(otherType)) { ... } // wildcard-aware comparison
	@endcode

	@note POD with no constructor: embedded verbatim in DataMessageHeader and
	other wire structs, so its size (32 bytes) must never change. Use NOTYPE for
	the empty/unset value.
	@ingroup Messaging
*/
struct PsyType {
	uint16 levels[PSYTYPELEVELS];	//!< Hierarchy levels, most significant first; 0 terminates, 0xFFFF is a wildcard.
	//! A type is valid if its root level is non-zero.
	bool isValid() {return (levels[0] != 0);}
	//! Exact byte-wise equality of all levels (wildcards NOT honoured; use matches() for that).
	bool operator==(const PsyType &othertype) const {
		return memcmp(levels, othertype.levels, sizeof(PsyType)) == 0;
	}
	//! Exact byte-wise inequality (wildcards NOT honoured).
	bool operator!=(const PsyType &othertype) const {
		return memcmp(levels, othertype.levels, sizeof(PsyType)) != 0;
	}
	//! Lexicographic level-by-level ordering, so PsyType can be used as a std::map/std::multimap key.
	bool operator<(const PsyType &othertype) const {
		for (uint32 n = 0; n < PSYTYPELEVELS; n++) {
			if (levels[n] < othertype.levels[n])
				return true;
			else if (levels[n] > othertype.levels[n])
				return false;
		}
		return false;
	}
	bool operator>(const PsyType &othertype) const {
		for (uint32 n = 0; n < PSYTYPELEVELS; n++) {
			if (levels[n] > othertype.levels[n])
				return true;
			else if (levels[n] < othertype.levels[n])
				return false;
		}
		return false;
	}
	uint16 operator[](int i) const {
		if ((i < 0) && (i >= PSYTYPELEVELS))
			return 0;
		return levels[i];
	}
	/*! Set an individual hierarchy level.
	@param i level index (0..PSYTYPELEVELS-1)
	@param value level value (0 terminates, 0xFFFF = wildcard)
	@return true if set */
	bool setLevel(int i, uint16 value) {
		if ((i < 0) && (i >= PSYTYPELEVELS))
			return false;
		levels[i] = value;
		return true;
	}
	/*! Wildcard-aware type matching used by the subscription system.
	Two types match if every level is either equal or 0xFFFF on either side.
	@param otherType the type to compare against
	@return true if the types match */
	bool matches(PsyType& otherType) const {
		for (uint32 n = 0; n < PSYTYPELEVELS; n++) {
			if ((levels[n] != otherType.levels[n]) && (levels[n] != 0xFFFF) && (otherType.levels[n] != 0xFFFF))
				return false;
		}
		return true;

			//v = levels[n] & otherType.levels[n];
			//if ( (v != (levels[n] > otherType.levels[n] ? otherType.levels[n] : levels[n])))
			//	return false;
		//uint64 *a = (uint64*)&levels;
		//uint64 *b = (uint64*)&otherType.levels;
		//uint64 v;
		//uint32 n, c = sizeof(levels) / sizeof(uint64);
		//for (n = 0; n < c; n++) {
		//	v = *a++ & *b++;
		//	if ( (v != (*a>*b?*b:*a)))
		//		return false;
		//}
		//return true;
	}
	//! Render as dotted decimal notation, e.g. "2.201.3"; empty string if invalid.
	std::string toString() {
		if (!levels[0])
			return "";
		std::stringstream ss;
		ss << levels[0];
		for (uint32 n = 1; n < PSYTYPELEVELS; n++) {
			if (levels[n])
				ss << '.' << levels[n];
		}
		return ss.str();
	}
	/*! Render as dotted notation, substituting readable names for level ids where available.
	@param subtypes map of level id → name; NULL falls back to numeric toString() */
	std::string toString(std::map<uint16, std::string>* subtypes) {
		if (!subtypes)
			return toString();
		if (!levels[0])
			return "";
		
		std::map<uint16, std::string>::iterator i, e = subtypes->end();
		std::stringstream ss;
		if ((i = subtypes->find(levels[0])) != e)
			ss << i->second;
		else
			ss << levels[0];
		for (uint32 n = 1; n < PSYTYPELEVELS; n++) {
			if (levels[n]) {
				if ((i = subtypes->find(levels[n])) != e)
					ss << '.' << i->second;
				else
					ss << '.' << levels[n];
			}
		}
		return ss.str();
	}
	/*! Parse dotted decimal notation (e.g. "2.201.3") into the level array.
	All levels are reset first. @param text dotted type string
	@return true if the result is a valid type */
	bool fromString(const char* text) {
		if (!text)
			return false;
		memset(levels, 0, sizeof(PsyType));

		const char* pstr = text;
		const char* src = text;
		char *temp = new char[16];
		uint32 n = 0;

		while (pstr = strstr(src, ".")) {
			if (pstr - src) {
				memcpy(temp, src, pstr - src);
				temp[pstr - src] = 0;
				levels[n] = atoi(temp);
				n++;
				if (n == PSYTYPELEVELS)
					return true;
			}
			src = pstr + 1;
		}
		pstr = src + strlen(src);
		if (pstr - src) {
			memcpy(temp, src, pstr - src);
			temp[pstr - src] = 0;
			levels[n] = atoi(temp);
			n++;
		}
		delete[] temp;
		return isValid();
	}
};

//! Number of hierarchy levels in a PsyContext.
#define PSYCONTEXTLEVELS 16

/*! @brief Hierarchical execution-context identifier.

	Structurally identical to PsyType (16 uint16 levels, dotted notation,
	0xFFFF wildcard) but semantically different: a PsyContext describes the
	situation/state a system is operating in (e.g. "dialog.greeting").
	Components can be active only in certain contexts, and messages can switch
	the current context via DataMessageHeader::contextchange. Unlike
	PsyType::matches(), PsyContext::matches() also treats level value 0 as a
	wildcard, so a more general context matches a more specific one.
	Use compare() to get the precise relationship (equal / supersedes /
	included / different root). Use NOCONTEXT for the empty value.

	@note POD embedded in wire structs — size must never change.
	@ingroup Messaging
*/
struct PsyContext {
	uint16 levels[PSYCONTEXTLEVELS];	//!< Hierarchy levels, most significant first; 0 terminates (and wildcards in matches()), 0xFFFF is a wildcard.
	//bool operator=(const PsyContext &othertype) {
	//	return memcpy(levels, othertype.levels, sizeof(PsyContext));
	//}
	bool isValid() {return (levels[0] != 0);}
	bool operator==(const PsyContext &othercontext) const {
		return memcmp(levels, othercontext.levels, sizeof(PsyContext)) == 0;
	}
	bool operator!=(const PsyContext &othercontext) const {
		return memcmp(levels, othercontext.levels, sizeof(PsyContext)) != 0;
	}
	bool operator<(const PsyContext &othercontext) const {
		for (uint32 n = 0; n < PSYCONTEXTLEVELS; n++) {
			if (levels[n] < othercontext.levels[n])
				return true;
			else if (levels[n] > othercontext.levels[n])
				return false;
		}
		return false;
	}
	bool operator>(const PsyContext &othercontext) const {
		for (uint32 n = 0; n < PSYCONTEXTLEVELS; n++) {
			if (levels[n] > othercontext.levels[n])
				return true;
			else if (levels[n] < othercontext.levels[n])
				return false;
		}
		return false;
	}
	uint16 operator[](int i) const {
		if ((i < 0) && (i >= PSYCONTEXTLEVELS))
			return 0;
		return levels[i];
	}
	bool setLevel(int i, uint16 value) {
		if ((i < 0) && (i >= PSYCONTEXTLEVELS))
			return false;
		levels[i] = value;
		return true;
	}
	/*! Wildcard-aware context matching: levels are considered matching when
	equal, or when either side is 0xFFFF or 0 (both act as wildcards here).
	@param othercontext the context to compare against
	@return true if the contexts match */
	bool matches(const PsyContext& othercontext) const {
		for (uint32 n = 0; n < PSYCONTEXTLEVELS; n++) {
			if ((levels[n] != othercontext.levels[n]) &&
				(levels[n] != 0xFFFF) &&
				(othercontext.levels[n] != 0xFFFF) &&
				(levels[n] != 0) &&
				(othercontext.levels[n] != 0)
				)
				return false;
		}
		return true;
	}
	std::string toString() {
		if (!levels[0])
			return "";
		std::stringstream ss;
		ss << levels[0];
		for (uint32 n = 1; n < PSYCONTEXTLEVELS; n++) {
			if (levels[n])
				ss << '.' << levels[n];
		}
		return ss.str();
	}
	std::string toString(std::map<uint16, std::string>* subcontexts) {
		if (!subcontexts)
			return toString();
		if (!levels[0])
			return "";

		std::map<uint16, std::string>::iterator i, e = subcontexts->end();
		std::stringstream ss;
		if ((i = subcontexts->find(levels[0])) != e)
			ss << i->second;
		else
			ss << levels[0];
		for (uint32 n = 1; n < PSYTYPELEVELS; n++) {
			if (levels[n]) {
				if ((i = subcontexts->find(levels[n])) != e)
					ss << '.' << i->second;
				else
					ss << '.' << levels[n];
			}
		}
		return ss.str();
	}
	bool fromString(const char* text) {
		if (!text)
			return false;
		memset(levels, 0, sizeof(PsyContext));

		const char* pstr = text;
		const char* src = text;
		char *temp = new char[16];
		uint32 n = 0;

		while (pstr = strstr(src, ".")) {
			if (pstr - src) {
				memcpy(temp, src, pstr - src);
				temp[pstr - src] = 0;
				levels[n] = atoi(temp);
				n++;
				if (n == PSYCONTEXTLEVELS)
					return true;
			}
			src = pstr + 1;
		}
		pstr = src + strlen(src);
		if (pstr - src) {
			memcpy(temp, src, pstr - src);
			temp[pstr - src] = 0;
			levels[n] = atoi(temp);
			n++;
		}
		delete[] temp;
		return isValid();
	}

	#define CONTEXT_OTHER_ROOT	0	//!< compare(): the contexts differ already at the root level.
	#define CONTEXT_EQUAL		1	//!< compare(): the contexts are equal (up to wildcards).
	#define CONTEXT_SUPERSEDES	2	//!< compare(): this context is more specific than / supersedes the other.
	#define CONTEXT_INCLUDED	3	//!< compare(): this context is more general and includes the other.

	/*! Classify the hierarchical relationship between this context and another.
	@param othercontext context to compare with
	@return one of CONTEXT_EQUAL, CONTEXT_SUPERSEDES, CONTEXT_INCLUDED, CONTEXT_OTHER_ROOT */
	uint8 compare(const PsyContext& othercontext) const {
		for (uint32 n = 0; n < PSYCONTEXTLEVELS; n++) {
			if ((levels[n] != othercontext.levels[n]) && (levels[n] != 0xFFFF) && (othercontext.levels[n] != 0xFFFF)) {
				if (n==0)
					return CONTEXT_OTHER_ROOT;
				else if (levels[n] == 0) {
					if (othercontext.levels[n] == 0)
						return CONTEXT_EQUAL;
					else
						return CONTEXT_INCLUDED;
				}
			//  included in the statement below
			//	else if (otherContext.levels[n] == 0)
			//		return CONTEXT_SUPERSEDES;
				else
					return CONTEXT_SUPERSEDES;
			}
		}
		return CONTEXT_EQUAL;
	}
};

static struct PsyType NOTYPE = { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };			//!< The empty/unset message type (isValid() == false).
static struct PsyContext NOCONTEXT = { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };	//!< The empty/unset context (isValid() == false).

#endif // TYPES_H
