

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  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 Utils.h
    @brief Cross-platform utility toolbox for CMSDK: threading, synchronization, shared memory, processes, sockets, files, strings, conversions and randomness.

    This header collects the OS-abstraction and general-purpose helper layer used
    throughout the CMSDK/Psyclone codebase. Nearly every subsystem (messaging,
    catalogs, spaces, network) builds on these primitives. All functions live in
    the cmlabs::utils namespace (except the logging classes in cmlabs) and are
    implemented for Windows, Linux and macOS; platform differences are hidden
    behind the WINDOWS / __APPLE__ preprocessor branches visible below. */
#if !defined(_UTILS_H_)
#define _UTILS_H_

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <sys/types.h>
#include <stdarg.h>
#include <iomanip>

#include "Types.h"
#include "Base64.h"

#ifdef WINDOWS
	#include <io.h>
//	#include <windows.h>
	#include <winsock2.h>
	#include <ws2tcpip.h>
	#include <iphlpapi.h>
	#include <iptypes.h>
	#include "Psapi.h"
	#include "direntwin.h"
	#include <process.h>
	// #include <Dbghelp.h> // needed for program trace only, link with Dbghelp.lib
#else
	#ifndef __APPLE__
	#include <semaphore.h>
	#endif
	#include <dlfcn.h>
	#include <errno.h>
	#include <sys/utsname.h>
	#include <sys/time.h>
	#include <pthread.h>
	#include <signal.h>
#ifdef __APPLE__
	#include <mach/mach.h>
	#include <mach/mach_time.h>
	#include <dispatch/dispatch.h>
#else
	#include <sys/prctl.h>
#endif
	#include <unistd.h>
	#include <time.h>
	#include <sys/mman.h>
	#include <sys/syscall.h>
#ifndef __APPLE__
	#include <sys/sysinfo.h>
#endif
	#include <sys/socket.h>
	#include <netdb.h>
	#include <net/if.h>
	#include <sys/ioctl.h>
	#include <dirent.h>
	#include <netinet/tcp.h>
	#include <sys/wait.h>
	#include <execinfo.h>
	#include <sys/resource.h>
	#include <limits>
//	#include <curses.h>
#endif

#ifdef WINDOWS
	#include <direct.h>
	#define GetCurrentDirEx _getcwd
#else
	//#include <unistd.h>
	#define GetCurrentDirEx getcwd
#endif

#define WINSHMEMSPACE		"Local"
//#define WINSHMEMSPACE		"Global"

#define MAXKEYNAMELEN		256
#define MAXVALUENAMELEN		1024
#define MAXCONTENTLEN		4196
#define MAXCOMMANDLINELEN	1024
#define MAXFILENAMELEN		256
#define MAXSHMEMNAMELEN		1024
#define MAXSCRIPTLEN		10*1024

#define THREAD_NONE			0
#define THREAD_TERMINATED	1
#define THREAD_INIT			2
#define THREAD_RUNNING		3
#define THREAD_PAUSED		4
#define THREAD_INTERRUPTED	5

#define THREAD_STATS_OFF	0
#define THREAD_STATS_AUTO	1
#define THREAD_STATS_ADHOC	2

#ifdef WINDOWS
//	#define Mutex HANDLE
//	#define NMutex HANDLE
//	#define Semaphore HANDLE
	#define ThreadHandle HANDLE
//	#define THREAD_FUNCTION static DWORD WINAPI
//	#define THREAD_FUNCTION DWORD WINAPI
	#define THREAD_RET DWORD
	typedef LPTHREAD_START_ROUTINE THREAD_FUNCTION;
	#define	THREAD_FUNCTION_CALL WINAPI
	#define THREAD_ARG LPVOID
	#define thread_ret_val(ret) return ret;
	#define DllExport __declspec(dllexport)
	#define MUTEX_INVALID NULL
	#define SOCKETWOULDBLOCK WSAEWOULDBLOCK
	#define SOCKETTRYAGAIN WSAEWOULDBLOCK
	#define abs64 _abs64
#else
//	#define Mutex pthread_mutex_t
//	#define NMutex sem_t *
//	#define Semaphore sem_t*
	#define ThreadHandle pthread_t
//	#define THREAD_FUNCTION void*(*)(void*)
	#define THREAD_RET void *
	typedef THREAD_RET (*THREAD_FUNCTION)(void *);
	#define	THREAD_FUNCTION_CALL 
	#define THREAD_ARG void*
	#define thread_ret_val(ret) pthread_exit((THREAD_RET)(intptr_t)ret);
	#define stricmp strcasecmp
	#define MUTEX_INVALID 0
	#define SOCKET int
	typedef struct sockaddr SOCKADDR;
	#define SOCKET_ERROR	-1
	#define INVALID_SOCKET	-1
	#define closesocket(X)	close(X)
	#define SOCKETWOULDBLOCK EINPROGRESS
	#define SOCKETTRYAGAIN EAGAIN
	#define abs64 llabs
	#define MUTEXMEMSIZE 64
	#define EVENTMEMSIZE 256
	#define SEMAPHOREMEMSIZE 256
	#define _strcmpi strcasecmp
	#define _strnicmp strnicmp
	#define DllExport
#endif

#ifndef SD_BOTH
	#define SD_BOTH 2
#endif

#define OSCPU_UNKNOWN 0
#define OSCPU_X86 1
#define OSCPU_AMD64 2
#define OSCPU_IA64 3

#define ERROR64 0xFFFFFFFFFFFFFFFFL
#define ERROR32 0xFFFFFFFF
#define ERROR16 0xFFFF
#define ERROR8 0xFF

#include "PsyTime.h"

namespace cmlabs {

//////////////////////////////////////////////////////////////
//                        INIT/EXIT                         //
//////////////////////////////////////////////////////////////

/*! @brief RAII guard whose single static instance triggers global utility cleanup at program exit.

    Constructing it installs nothing special; its destructor (run during static
    de-initialization) releases the process-wide maps of named mutexes,
    semaphores, events and shared-memory handles so the OS objects are not
    leaked. Users normally never instantiate this themselves. */
class CleanShutdown {
public:
	/*! @brief Default constructor; no side effects. */
	CleanShutdown();
	/*! @brief Destroys all lazily-created global utility maps via ClearUtilsMaps(). */
	~CleanShutdown();
};

/*! @brief Free all lazily-allocated global registries (mutex/semaphore/event/shared-memory maps).
    @return true when the maps were cleared (idempotent; safe to call more than once).
    @note Called automatically by CleanShutdown at exit; only call manually when
          deliberately tearing down all utils state, e.g. before unloading a plugin. */
bool ClearUtilsMaps();

//////////////////////////////////////////////////////////////
//                         Logging                          //
//////////////////////////////////////////////////////////////

#define LOG_NOTOPIC		0
#define LOG_SYSTEM		1
#define LOG_NETWORK		2
#define LOG_MEMORY		3
#define LOG_PROCESS		4
#define LOG_TOPIC5		5
#define LOG_TOPIC6		6
#define LOG_TOPIC7		7
#define LOG_TOPIC8		8
#define LOG_TOPIC9		9
#define LOG_TOPIC10		10
#define LOG_TOPIC11		11
#define LOG_MAXCOUNT	12

#define LOGPRINT	1
#define LOGDEBUG	2

/*! @brief Translate a CMSDK datatype id (e.g. from a DataMessage) into its human-readable name.
    @param datatype Numeric datatype constant.
    @return Type name such as "Message" or "Image"; an "unknown" string for unrecognized ids. */
std::string GetDataTypeName(uint32 datatype);
/*! @brief Inverse of GetDataTypeName(): look up the numeric datatype id for a type name.
    @param typeName NUL-terminated, case-insensitive type name.
    @return Datatype id, or 0 when the name is not recognized. */
uint32 GetDataTypeID(const char* typeName);

// #define GETLOGTEXT(l) (char*)l+sizeof(LogEntry)
/*! @brief Wire/storage layout of one log record: fixed header immediately followed by the message text.

    The struct is a variable-length blob: @c size covers the header plus the
    text payload placed directly after the struct in memory, which makes
    entries trivially copyable across shared memory and sockets. */
struct LogEntry {
	uint32	size;		// 
	uint32	cid;		// LOGENTRYID
	uint64	time;		// 
	uint32	source;		// 
	uint8	subject;	// 
	uint8	level;		// 
	uint8	type;		// 
	/*! @brief Access the text payload stored after the header.
	    @param[out] len Receives the payload length in bytes.
	    @return Pointer into this entry's trailing text (not separately allocated). */
	const char* getText(uint32& len);
	/*! @brief Copy @p len bytes of @p text into the payload area and update @c size.
	    @param text Source text (need not be NUL-terminated).
	    @param len Number of bytes to copy.
	    @return true on success. @note The caller must have allocated the entry large enough. */
	bool setText(char* text, uint32 len);
	/*! @brief Serialize the entry (header fields + text) as a JSON object string. @return JSON text. */
	std::string toJSON();
	/*! @brief Serialize the entry as an XML fragment. @return XML text. */
	std::string toXML();
};

/*! @brief Callback interface for receiving log entries produced through LogSystem.

    Implement logEntry() and register the object with LogSystem::SetLogReceiver()
    to redirect all logging (e.g. into the Psyclone system log space) instead of
    stdout/file output. */
class LogReceiver {
public:
	LogReceiver() {}
//	virtual bool logPrint(uint32 source, uint8 subject, uint8 level, std::string text, uint64 time) = 0;
//	virtual bool logDebug(uint32 source, uint8 subject, uint8 level, std::string text, uint64 time) = 0;
	/*! @brief Handle one log record. @param entry Borrowed pointer, valid only for the duration of the call. @return true if consumed. */
	virtual bool logEntry(LogEntry* entry) = 0;
};

/*! @brief Process-wide singleton logging hub with per-topic verbosity/debug levels.

    Log calls go through the LogPrint / LogDebug macros which forward to the
    static LogSystemPrint()/LogSystemDebug() printf-style entry points. Output
    can go to stdout, a file, and/or a registered LogReceiver. Topics (subjects)
    are the LOG_* constants above; each has independent verbose and debug
    level thresholds. */
class LogSystem {
public:
	LogSystem();
	~LogSystem();

	/*! @brief Lazily-created global instance used by all static functions. */
	static LogSystem* LogSingleton;
	/*! @brief Register a receiver that gets every accepted LogEntry. @param rec Receiver (not owned). @return true on success. */
	static bool SetLogReceiver(LogReceiver* rec);

	/*! @brief Direct log output to a file.
	    @param logfile Path of the log file to append to.
	    @param printOut Also keep printing to stdout when true.
	    @return true if the file could be set. */
	static bool SetLogFileOutput(const char* logfile, bool printOut = true);
	/*! @brief Set the debug level threshold for all topics. @param level Messages with level <= this are emitted. */
	static bool SetLogLevelDebug(uint8 level);
	/*! @brief Set the debug level threshold for one topic. @param subject LOG_* topic id. @param level Threshold. */
	static bool SetLogLevelDebug(uint8 subject, uint8 level);
	/*! @brief Set the verbose (print) level threshold for all topics. @param level Threshold. */
	static bool SetLogLevelVerbose(uint8 level);
	/*! @brief Set the verbose (print) level threshold for one topic. @param subject LOG_* topic id. @param level Threshold. */
	static bool SetLogLevelVerbose(uint8 subject, uint8 level);

	/*! @brief printf-style informational logging (usually invoked via the LogPrint macro).
	    @param source Numeric id of the logging component.
	    @param subject LOG_* topic.
	    @param level Importance; emitted when <= the topic's verbose threshold.
	    @param formatstring printf format followed by matching varargs.
	    @return true if the entry was emitted. */
	static bool LogSystemPrint(uint32 source, uint8 subject, uint8 level, const char *formatstring, ... );
	/*! @brief printf-style debug logging (usually invoked via the LogDebug macro); same parameters as LogSystemPrint() but gated on the debug thresholds. */
	static bool LogSystemDebug(uint32 source, uint8 subject, uint8 level, const char *formatstring, ... );

	uint8 logLevelVerbose[LOG_MAXCOUNT];
	uint8 logLevelDebug[LOG_MAXCOUNT];
	LogReceiver* logReceiverObj;
	char* logfile;
	bool printToStdOut;
};

#define LogPrint LogSystem::LogSystemPrint
#define LogDebug LogSystem::LogSystemDebug

namespace utils {

/** @defgroup utils Utility functions and objects
*  Cross-platform helper layer of the CMSDK: synchronization primitives,
*  threads and processes, shared memory, timers, bit fields, sockets and name
*  lookup, registry access (Windows), file I/O, rich string/text manipulation,
*  numeric parsing/formatting and random numbers. Functions are grouped below
*  by theme. All of them are plain free functions in cmlabs::utils unless
*  noted otherwise.
*
*  @par Why this layer exists
*  Everything above it in the CMSDK — @ref Memory, @ref Threading,
*  @ref Messaging, the request fabric — must behave identically on Windows,
*  Linux and macOS. utils is where the platform differences are absorbed
*  exactly once: one Mutex/Semaphore API over CRITICAL_SECTION vs
*  pthread_mutex/named semaphores, one CreateThread over Win32 vs pthreads,
*  one shared-memory primitive over CreateFileMapping vs shm_open/mmap, one
*  socket/name-lookup wrapper over WinSock vs BSD sockets. The rest — the
*  Text* string toolkit, StringFormat(), ReadAFile()/WriteAFile(), the
*  Ascii2* parsers, WaitQueue/TimeQueue — exists because CMSDK predates the
*  std:: equivalents (or none exist) and because the codebase needs one
*  consistent, C-string-friendly way to do these chores everywhere.
*
*  @par Why not std:: / OS calls directly
*  Portability and consistency: locale-independent numeric parsing
*  (Ascii2Float64 always uses '.'), identical text-splitting semantics on
*  every platform, cross-process @e named mutexes/semaphores (which std has
*  no equivalent of), and integration — the shared-memory and semaphore
*  helpers here are the exact primitives the @ref Memory segments and queues
*  are built on.
*
*  @par Common tasks
*  @code
*  using namespace cmlabs::utils;
*
*  // String formatting and manipulation
*  std::string s = StringFormat("%u items in %.2f s", n, secs);
*  std::vector<std::string> parts = TextListSplit("a, b,,c", ",", false, true); // {"a","b","c"}
*  std::string joined = TextJoin(parts, ";");
*  std::string up = TextUppercase(TextTrim("  hello  ").c_str());    // "HELLO"
*
*  // File I/O
*  std::string cfg = ReadAFileString("config.xml");                  // text, empty on error
*  uint32 len; char* raw = ReadAFile("image.bin", len, true);        // binary; delete [] raw
*  WriteAFile("out.txt", s.c_str(), (uint32)s.size());
*
*  // Numeric parsing (locale-independent)
*  int64 v = Ascii2Int64("12345");
*  float64 f = Ascii2Float64("3.14");    // always '.' decimal point
*
*  // Cross-thread/-process synchronisation
*  Mutex m("my.global.lock");            // named => visible to other processes
*  if (m.enter(1000, __FUNCTION__)) {
*      // ... critical section ...
*      m.leave();
*  }
*  @endcode
*
*  @note char*-returning helpers generally allocate with `new char[]` and the
*  caller must `delete []`; prefer the std::string variants where both exist.
*  @{
*/

/*! @brief Run the built-in self test of the utils module. @return true when all sub-tests pass. */
bool UtilsTest();

// bool GetSystemName(uint32 id, const char* title, char* name, uint32 size);



//////////////////////////////////////////////////////////////
//                         Mutexes                          //
//////////////////////////////////////////////////////////////

#ifdef WINDOWS
	#define SharedMemoryFileHandleMapType std::map<char*, HANDLE>
#else
	#define SharedMemoryFileHandleMapType std::map<void*, std::string>
#endif
static SharedMemoryFileHandleMapType* SharedMemoryFileHandleMap = NULL;

static uint16 SharedSystemInstance = 0;

/*! @name Synchronization primitives (mutexes, semaphores, events, drum beats)
    Named primitives are backed by OS objects shared between processes (Windows
    kernel objects, POSIX shared memory + pthread process-shared objects, or
    dispatch/mach objects on macOS); unnamed ones are process-local.
    @{ */

/*! @brief Set the instance number used to namespace shared OS objects, allowing several independent CMSDK systems on one host.
    @param inst Instance number (0 = default namespace).
    @return true on success. */
bool SetSharedSystemInstance(uint32 inst);
/*! @brief Get the current shared-system instance number. @return Instance set via SetSharedSystemInstance(), default 0. */
uint32 GetSharedSystemInstance();

// https://stackoverflow.com/questions/44807302/create-c-timer-in-macos/52905687#52905687

/*! @brief Callback invoked on every drum-beat tick.
    @param id Drum beat id it was registered under.
    @param count Tick counter, increasing from 1.
    @return Return false to request no further processing of this tick. */
typedef bool (* DrumBeatFunc)(uint32 id, uint32 count);

/*! @brief Bookkeeping record for one periodic "drum beat" timer.
    The platform-specific @c handle is a Windows timer-queue timer, a macOS
    dispatch source, or a POSIX @c timer_t. */
struct DrumBeatInfo {
	uint32 id;
	uint64 createdTime;
	uint64 started;
	uint32 interval;
	DrumBeatFunc func;
	uint32 count;
	#ifdef WINDOWS
		HANDLE handle;
	#else
		#ifdef __APPLE__
			dispatch_source_t handle;
		#else
			timer_t handle;
		#endif
	#endif
};

static std::map<uint32, DrumBeatInfo>* DrumBeatMap = NULL;

/*! @brief Create a periodic timer ("drum beat") that calls @p func every @p interval ms.
    @param id Caller-chosen unique id for the beat.
    @param interval Period in milliseconds.
    @param func Callback to invoke on each tick.
    @param autostart Start immediately when true; otherwise call StartDrumBeat().
    @return true if the timer was created. */
bool CreateDrumBeat(uint32 id, uint32 interval, DrumBeatFunc func, bool autostart = false);
/*! @brief Start (or resume) a previously created drum beat. @param id Beat id. @return true on success. */
bool StartDrumBeat(uint32 id);
/*! @brief Stop a running drum beat without destroying it. @param id Beat id. @return true on success. */
bool StopDrumBeat(uint32 id);
/*! @brief Destroy a drum beat and release its OS timer. @param id Beat id. @return true on success. */
bool EndDrumBeat(uint32 id);

/*! @brief Recursive mutual-exclusion lock, optionally named for cross-process use.

    Unnamed mutexes are process-local; named mutexes are created in shared
    memory / as kernel objects so multiple processes can synchronize on the
    same name. Prefer the timeout overload of enter() in production code so a
    dead peer cannot deadlock the caller forever. */
class Mutex {
public:
	/*! @brief Create an anonymous, process-local mutex. */
	Mutex();
	/*! @brief Create or open a named, cross-process mutex.
	    @param name Global name (namespaced by the shared system instance).
	    @param force Re-initialize the underlying object even if it already exists. */
	Mutex(const char* name, bool force = false);
	~Mutex();
	/*! @brief Block until the mutex is acquired. @return true when acquired. */
	bool enter();
	/*! @brief Acquire with a timeout.
	    @param timeout Max wait in milliseconds.
	    @param errorMsg Optional label (typically __FUNCTION__) logged when the wait times out.
	    @return true when acquired, false on timeout/error. */
	bool enter(uint32 timeout, const char* errorMsg = NULL);
	/*! @brief Release the mutex. @return true on success. */
	bool leave();
//	bool destroy();
protected:
	char *name;
	bool created;
	uint32 osid;
	uint32 total;
	uint32 count;
	#ifdef WINDOWS
		HANDLE mutex;
	#else
		//sem_t* semaphore;
		pthread_mutex_t* mutex;
	#endif
};


/*! @brief Counting semaphore, optionally named for cross-process use.

    On macOS an unnamed semaphore uses libdispatch (dispatch_semaphore_t) while
    named ones are emulated in shared memory, because POSIX unnamed semaphores
    are unsupported there — hence the void* @c semaphore_impl member. */
class Semaphore {
public:
	/*! @brief Create an anonymous semaphore. @param maxCount Maximum count (Windows honours it strictly). */
	Semaphore(uint32 maxCount = 100);
	/*! @brief Create or open a named, cross-process semaphore. @param name Global name. @param maxCount Maximum count. */
	Semaphore(const char* name, uint32 maxCount = 100);
	~Semaphore();
	/*! @brief Block until the semaphore can be decremented. @return true on success. */
	bool wait();
	/*! @brief Wait with a timeout. @param timeout Max wait in milliseconds. @return true when acquired, false on timeout. */
	bool wait(uint32 timeout);
	/*! @brief Increment (release) the semaphore, waking one waiter. @return true on success. */
	bool signal();
//	bool destroy();
	char *name;
protected:
	#ifdef WINDOWS
		HANDLE semaphore;
	#else
		#ifdef __APPLE__
			void* semaphore_impl;  /* dispatch_semaphore_t when name==NULL, else char* to shared memory */
		#else
			sem_t* semaphore;
		#endif
	#endif
};

/*! @brief Auto-reset notification event (condition variable style), optionally named for cross-process use.

    Unlike a semaphore, signals are not counted: a signal wakes waiters that
    are currently blocked in waitNext(); there is no memory of past signals. */
class Event {
public:
	/*! @brief Create an anonymous, process-local event. */
	Event();
	/*! @brief Create or open a named, cross-process event. @param name Global name. */
	Event(const char* name);
	~Event();
	/*! @brief Block until the next signal() occurs. @return true when signalled. */
	bool waitNext();
	/*! @brief Wait for a signal with a timeout. @param timeout Max wait in milliseconds. @return true when signalled, false on timeout. */
	bool waitNext(uint32 timeout);
	/*! @brief Wake all threads currently waiting on this event. @return true on success. */
	bool signal();
//	bool destroy();
protected:
	char *name;
	#ifdef WINDOWS
		HANDLE event;
	#else
		pthread_cond_t* event;
		pthread_mutex_t* mutex;
	#endif
};

/*! @brief Acquire a named global mutex, creating it on first use.
    @param name Mutex name. @param ms Timeout in milliseconds.
    @param autocreate Create the mutex if it does not yet exist.
    @return true when acquired. */
bool EnterMutex(const char* name, uint32 ms, bool autocreate = true);
/*! @brief Release a named global mutex previously acquired with EnterMutex(). @param name Mutex name. @return true on success. */
bool LeaveMutex(const char* name);
/*! @brief Destroy a named global mutex and remove it from the registry. @param name Mutex name. @return true on success. */
bool DestroyMutex(const char* name);

/*! @brief Look up (and optionally create) a named semaphore in the global registry.
    @param name Semaphore name. @param autocreate Create when missing.
    @return Registry-owned pointer (do not delete), or NULL. */
Semaphore* GetSemaphore(const char* name, bool autocreate = true);
/*! @brief Wait on a named global semaphore. @param name Semaphore name. @param ms Timeout in ms. @param autocreate Create when missing. @return true when acquired. */
bool WaitForSemaphore(const char* name, uint32 ms, bool autocreate = true);
/*! @brief Signal a named global semaphore. @param name Semaphore name. @return true on success. */
bool SignalSemaphore(const char* name);
/*! @brief Destroy a named global semaphore. @param name Semaphore name. @return true on success. */
bool DestroySemaphore(const char* name);

/*! @brief Wait for the next signal on a named global event. @param name Event name. @param ms Timeout in ms. @param autocreate Create when missing. @return true when signalled. */
bool WaitNextEvent(const char* name, uint32 ms, bool autocreate = true);
/*! @brief Signal a named global event. @param name Event name. @return true on success. */
bool SignalEvent(const char* name);
/*! @brief Destroy a named global event. @param name Event name. @return true on success. */
bool DestroyEvent(const char* name);

/*! @} */

static Mutex* SharedMemoryMutexMapMutex = NULL;
static std::map<std::string, Mutex*>* SharedMemoryMutexMap = NULL;
typedef std::pair<std::string, Mutex*> SharedMemoryMutexMapPair;
static Mutex* SharedMemorySemaphoreMapMutex = NULL;
static std::map<std::string, Semaphore*>* SharedMemorySemaphoreMap = NULL;
typedef std::pair<std::string, Semaphore*> SharedMemorySemaphoreMapPair;
static Mutex* SharedMemoryEventMapMutex = NULL;
static std::map<std::string, Event*>* SharedMemoryEventMap = NULL;
typedef std::pair<std::string, Event*> SharedMemoryEventMapPair;

#ifdef WINDOWS
struct ProcessData {
	ProcessData() { hOutRead = NULL; hErrRead = NULL; }
	PROCESS_INFORMATION procInfo;
	STARTUPINFO si;
	HANDLE hOutRead;	//!< Parent read-end of the child's redirected stdout (NULL = not captured).
	HANDLE hErrRead;	//!< Parent read-end of the child's redirected stderr (NULL = not captured).
};
static std::map<uint32, ProcessData*>* ProcessInformationMap = NULL;
typedef std::pair <uint32, ProcessData*> Proc_Pair;
static HANDLE ghJob = NULL;
#endif

/*! @name Timers and queues
    @{ */

/*! @brief One scheduled entry inside a Timer: id, active window and platform timer handle. */
struct TimerSchedule {
	uint32 globalID;
	uint32 id;
	uint64 start;
	uint64 end;
	uint32 interval;
	#ifdef WINDOWS
		HANDLE handle;
	#else
		#ifdef __APPLE__
			dispatch_source_t handle;
		#else
			timer_t handle;
		#endif
	#endif
};

/*! @brief A single timer expiry: which timer fired and when. */
struct TimerTrigger {
	uint32 id;
	uint64 time;
};

/*! @brief Multiplexing timer: schedule many periodic timers and consume their expiries from one queue.

    Each addTimer() registers an OS timer (timer queue / dispatch source /
    POSIX timer). Expiries are pushed into an internal trigger queue which a
    consumer drains via waitForTimer(), giving a select()-like wait over any
    number of timers from a single thread. */
class Timer {
public:
	/*! @brief Global registry mapping globalID to live Timer instances, used by the OS callbacks. */
	static std::map<uint32, Timer*>* timers;

	Timer();
	~Timer();

	/*! @brief Register a periodic timer.
	    @param id Caller-chosen id reported back by waitForTimer().
	    @param interval Period in milliseconds.
	    @param start Optional absolute start time (ms epoch); 0 = now.
	    @param end Optional absolute end time after which the timer stops; 0 = never.
	    @return true on success. */
	bool addTimer(uint32 id, uint32 interval, uint64 start = 0, uint64 end = 0);
	/*! @brief Manually inject an expiry for timer @p id, as if it had fired now. @return true on success. */
	bool triggerTimer(uint32 id);
	/*! @brief Wait for the next expiry of any registered timer.
	    @param timeout Max wait in milliseconds.
	    @param[out] id Receives the id of the timer that fired.
	    @param[out] time Receives the expiry timestamp (ms).
	    @return true when a trigger was consumed, false on timeout. */
	bool waitForTimer(uint32 timeout, uint32& id, uint64& time);
	/*! @brief Unregister a timer and cancel its OS timer. @param id Timer id. @return true on success. */
	bool removeTimer(uint32 id);

private:
	uint32 globalID;
	Mutex mutex;
	Semaphore semaphore;
	std::queue<TimerTrigger*> triggers;
	std::map<uint32, TimerSchedule*> schedules;
	std::list<TimerSchedule*> oldSchedules;
};

#ifdef WINDOWS
	/*! @brief Windows timer-queue callback trampoline; routes the expiry into the owning Timer's trigger queue. */
	void CALLBACK TimerCallback(PVOID arg, BOOLEAN TimerOrWaitFired);
#else
	/*! @brief POSIX signal-based timer callback trampoline (SIGEV_SIGNAL); routes the expiry into the owning Timer's trigger queue. */
   static void TimerCallback(int sig, siginfo_t *siginfo, void *context);
#endif
/*! @brief Self test for the Timer class. @return true when all checks pass. */
bool UnitTest_Timer();
/*! @brief Aggregate self test for miscellaneous utils functionality. @return true when all checks pass. */
bool UnitTest_Utils();

//////////////////////////////////////////////////////////////
//                       Wait Queue                         //
//////////////////////////////////////////////////////////////

/*! @brief Thread-safe FIFO queue with blocking waits, the workhorse producer/consumer channel in CMSDK.

    All operations take an internal mutex with a 200 ms timeout and return
    false rather than deadlock if it cannot be acquired. A semaphore is
    signalled on every add() so consumers can block in
    waitForAndTakeFirst()/waitForAndPeekFirst() without polling.
    @tparam T Element type (copied by value). For heap pointers prefer
    WaitQueuePointer, which deletes leftovers on clear(). */
template <typename T>
class WaitQueue {
public:
	WaitQueue() {}
	virtual ~WaitQueue() {}

	/*! @brief Append an entry and wake one waiting consumer. @param entry Value to enqueue. @return true on success. */
	bool add(T entry) {
		if (!mutex.enter(200, __FUNCTION__))
			return false;
		internalQueue.push(entry);
		semaphore.signal();
		mutex.leave();
		return true;
	}
	/*! @brief Number of queued entries. @return Count, or 0 when the lock could not be taken. */
	uint32 getCount() {
		uint32 size;
		if (!mutex.enter(200, __FUNCTION__))
			return 0;
		size = (uint32)internalQueue.size();
		mutex.leave();
		return size;
	}
	/*! @brief Copy the front entry without removing it. @param[out] first Receives the front value. @return false when empty. */
	bool peekFirst(T& first) {
		if (!mutex.enter(200, __FUNCTION__))
			return false;
		if (!internalQueue.size()) {
			mutex.leave();
			return false;
		}
		first = internalQueue.front();
		mutex.leave();
		return true;
	}
	/*! @brief Remove and return the front entry. @param[out] first Receives the front value. @return false when empty. */
	bool takeFirst(T& first) {
		if (!mutex.enter(200, __FUNCTION__))
			return false;
		if (!internalQueue.size()) {
			mutex.leave();
			return false;
		}
		first = internalQueue.front();
		internalQueue.pop();
		mutex.leave();
		return true;
	}
	/*! @brief Block up to @p timeoutMS for an entry and peek it without removal.
	    @param[out] first Receives the front value. @param timeoutMS Max wait in ms. @return true when an entry was available. */
	bool waitForAndPeekFirst(T& first, uint32 timeoutMS) {
		if (!mutex.enter(200, __FUNCTION__))
			return false;
		if (internalQueue.size()) {
			first = internalQueue.front();
			mutex.leave();
			return true;
		}
		mutex.leave();
		if (!semaphore.wait(timeoutMS))
			return false;
		if (!mutex.enter(200, __FUNCTION__))
			return false;
		if (internalQueue.size()) {
			first = internalQueue.front();
			mutex.leave();
			return true;
		}
		else {
			mutex.leave();
			return false;
		}
	}
	/*! @brief Block up to @p timeoutMS for an entry and dequeue it.
	    @param[out] first Receives the value. @param timeoutMS Max wait in ms. @return true when an entry was taken.
	    @note A race between the semaphore wait and re-lock can rarely yield false even after a signal; callers should loop. */
	bool waitForAndTakeFirst(T& first, uint32 timeoutMS) {
		if (!mutex.enter(200, __FUNCTION__))
			return false;
		if (internalQueue.size()) {
			first = internalQueue.front();
			internalQueue.pop();
			mutex.leave();
			return true;
		}
		mutex.leave();
		if (!semaphore.wait(timeoutMS))
			return false;
		if (!mutex.enter(200, __FUNCTION__))
			return false;
		if (internalQueue.size()) {
			first = internalQueue.front();
			internalQueue.pop();
			mutex.leave();
			return true;
		}
		else {
			mutex.leave();
			return false;
		}
	}
	/*! @brief Discard all queued entries. @return true on success. */
	virtual bool clear() {
		if (!mutex.enter(200, __FUNCTION__))
			return false;
		std::queue<T> empty;
		std::swap(internalQueue, empty);
		mutex.leave();
		return true;
	}

protected:
	Mutex mutex;
	Semaphore semaphore;
	std::queue<T> internalQueue;
};

/*! @brief WaitQueue specialization for owned heap pointers: clear()/destructor delete remaining entries.
    @tparam T Pointer type (e.g. Message*). NULL is returned on timeout, so NULL must not be a valid element. */
template <typename T>
class WaitQueuePointer : public WaitQueue<T> {
public:
	WaitQueuePointer() {}
	virtual ~WaitQueuePointer() { clear(); }

	/*! @brief Convenience overload: dequeue with timeout, returning NULL instead of using an out-parameter.
	    @param timeoutMS Max wait in ms. @return Front pointer (ownership transferred) or NULL on timeout. */
	T waitForAndTakeFirst(uint32 timeoutMS) {
		T first;
		if (WaitQueue<T>::waitForAndTakeFirst(first, timeoutMS))
			return first;
		else
			return NULL;
	}

	/*! @brief Delete every queued pointer and empty the queue. @return true on success. */
	virtual bool clear() {
		if (!WaitQueue<T>::mutex.enter(200, __FUNCTION__))
			return false;
		while (WaitQueue<T>::internalQueue.size()) {
			delete(WaitQueue<T>::internalQueue.front());
			WaitQueue<T>::internalQueue.pop();
		}
		WaitQueue<T>::mutex.leave();
		return true;
	}
};


//////////////////////////////////////////////////////////////
//                       Time Queue                         //
//////////////////////////////////////////////////////////////

/*! @brief One (time, entry) pair inside a TimeQueue. */
template <typename T>
struct TimeQueueEntry {
	uint64 time;
	T entry;
};

/*! @brief Thread-safe queue of entries ordered by due time; entries become retrievable once their timestamp passes.
    @tparam T Element type (copied by value); see TimeQueuePointer for owned heap pointers. */
template <typename T>
class TimeQueue {
public:
	TimeQueue() {}
	virtual ~TimeQueue() {}

	/*! @brief Insert an entry sorted by its due time. @param time Due time (ms, GetTimeNow() scale). @param entry Value to schedule. @return true on success. */
	bool add(uint64 time, T entry) {
		if (!mutex.enter(200, __FUNCTION__))
			return false;
		TimeQueueEntry<T> newEntry;
		newEntry.time = time;
		newEntry.entry = entry;
		typename std::list< TimeQueueEntry<T> >::iterator i = internalList.begin(),
			e = internalList.end();
		while (i != e) {
			if (time < (*i).time) {
				internalList.insert(i, newEntry);
				mutex.leave();
				return true;
			}
			i++;
		}
		internalList.push_back(newEntry);
		mutex.leave();
		return true;
	}
	/*! @brief Number of scheduled entries. @return Count, or 0 when the lock could not be taken. */
	uint32 getCount() {
		uint32 size;
		if (!mutex.enter(200, __FUNCTION__))
			return 0;
		size = (uint32)internalList.size();
		mutex.leave();
		return size;
	}
	/*! @brief Pop the earliest entry if its due time has passed (non-blocking).
	    @param[out] entry Receives the due entry. @return true when an entry was due and removed. */
	bool getNextEntryDue(T& entry) {
		if (!mutex.enter(200, __FUNCTION__))
			return false;
		if (!internalList.size()) {
			mutex.leave();
			return false;
		}
		uint64 now = GetTimeNow();
		TimeQueueEntry<T> first = internalList.front();
		if (first.time < now) {
			internalList.pop_front();
			entry = first.entry;
			mutex.leave();
			return true;
		}
		mutex.leave();
		return false;
	}
	/*! @brief Discard all scheduled entries. @return true on success. */
	virtual bool clear() {
		if (!mutex.enter(200, __FUNCTION__))
			return false;
		std::list< TimeQueueEntry<T> > empty;
		std::swap(internalList, empty);
		mutex.leave();
		return true;
	}

protected:
	Mutex mutex;
	std::list< TimeQueueEntry<T> > internalList;
};

/*! @brief TimeQueue specialization for owned heap pointers: clear()/destructor delete remaining entries.
    @tparam T Pointer type; NULL means "nothing due", so NULL must not be a valid element. */
template <typename T>
class TimeQueuePointer : public TimeQueue<T> {
public:
	TimeQueuePointer() {}
	virtual ~TimeQueuePointer() { clear(); }

	/*! @brief Pop the earliest due entry. @return The entry (ownership transferred) or NULL when nothing is due. */
	T getNextEntryDue() {
		T first;
		if (TimeQueue<T>::getNextEntryDue(first))
			return first;
		else
			return NULL;
	}

	/*! @brief Delete every scheduled pointer and empty the queue. @return true on success. */
	virtual bool clear() {
		if (!TimeQueue<T>::mutex.enter(200, __FUNCTION__))
			return false;
		typename std::list< TimeQueueEntry<T> >::iterator i = TimeQueue<T>::internalList.begin(),
			e = TimeQueue<T>::internalList.end();
		while (i != e) {
			delete((*i).entry);
			i++;
		}
		TimeQueue<T>::internalList.clear();
		TimeQueue<T>::mutex.leave();
		return true;
	}
};


//////////////////////////////////////////////////////////////
//                      Shared Memory                       //
//////////////////////////////////////////////////////////////

/*! @} */

/*! @name Shared memory
    Named segments are implemented with CreateFileMapping on Windows and
    shm_open/mmap on POSIX; names are prefixed with the shared system instance
    so independent CMSDK deployments do not collide.
    @{ */

/*! @brief Create a named shared memory segment and map it into this process.
    @param name Global segment name.
    @param size Size in bytes.
    @param force Recreate the segment even if one with this name already exists.
    @return Pointer to the mapped memory, or NULL on failure. */
char* CreateSharedMemorySegment(const char* name, uint64 size, bool force = false);
/*! @brief Open and map an existing named shared memory segment.
    @param name Global segment name. @param size Expected size in bytes.
    @return Pointer to the mapped memory, or NULL when it does not exist. */
char* OpenSharedMemorySegment(const char* name, uint64 size);
/*! @brief Unmap a segment previously created/opened here.
    @param data Pointer returned by Create/OpenSharedMemorySegment(). @param size Segment size in bytes.
    @return true on success. @note The named object survives until all processes close it. */
bool CloseSharedMemorySegment(char* data, uint64 size);
// Destroy named shared memory segment
// bool DestroySharedMemorySegment(char* data, uint32 size);

/*! @} */

/*! @name Bit field operations
    Helpers for compact allocation bitmaps (used e.g. by the shared-memory
    block allocators). Bit 0 is the least significant bit of the first byte.
    @{ */

/*! @brief Convert a 64-bit value from network to host byte order. @param input Big-endian value. @return Host-order value. */
uint64 ntoh64(const uint64 *input);
/*! @brief Convert a 64-bit value from host to network byte order. @param input Host-order value. @return Big-endian value. */
uint64 hton64(const uint64_t *input);

/*! @brief Compute the byte size needed for a bitfield of @p bitsize bits, rounded up to a 32-bit boundary.
    @param bitsize Number of bits. @return Byte size. */
uint32 Calc32BitFieldSize(uint32 bitsize);
/*! @brief Zero the whole bitfield, marking every bit as free. @param bitfield Field data. @param bytesize Field size in bytes. @return true on success. */
bool Reset32BitField(char* bitfield, uint32 bytesize);
/*! @brief Find the first 0 (free) bit.
    @param bitfield Field data. @param bytesize Field size in bytes. @param[out] loc Receives the bit index.
    @return true when a free bit exists. */
bool GetFirstFreeBitLoc(const char* bitfield, uint32 bytesize, uint32& loc);
/*! @brief Find the first run of @p num consecutive 0 bits.
    @param bitfield Field data. @param bytesize Field size in bytes. @param num Run length required. @param[out] loc Receives the start bit index.
    @return true when such a run exists. */
bool GetFirstFreeBitLocN(const char* bitfield, uint32 bytesize, uint32 num, uint32& loc);
/*! @brief Set bit @p loc to @p value. @param loc Bit index. @param value 0 or 1. @param bitfield Field data. @param bytesize Field size in bytes. @return false when out of range. */
bool SetBit(uint32 loc, bit value, char* bitfield, uint32 bytesize);
/*! @brief Set @p num consecutive bits starting at @p loc to @p value.
    @param loc First bit index. @param num Run length. @param value 0 or 1. @param bitfield Field data. @param bytesize Field size in bytes. @return false when out of range. */
bool SetBitN(uint32 loc, uint32 num, bit value, char* bitfield, uint32 bytesize);
/*! @brief Read bit @p loc. @param loc Bit index. @param bitfield Field data. @param bytesize Field size in bytes. @param[out] val Receives the bit. @return false when out of range. */
bool GetBit(uint32 loc, const char* bitfield, uint32 bytesize, bit& val);
/*! @brief Find the highest set (occupied) bit. @param bitfield Field data. @param bytesize Field size in bytes. @param[out] loc Receives the bit index. @return false when the field is all zero. */
bool GetLastOccupiedBitLoc(const char* bitfield, uint32 bytesize, uint32& loc);

/*! @brief Render the first @p size bits as a '0'/'1' string, for debugging.
    @param bitfield Field data. @param bytesize Field size in bytes. @param size Number of bits to render. @return Text representation. */
std::string GetBitFieldAsString(const char* bitfield, uint32 bytesize, uint32 size);
/*! @brief Like GetBitFieldAsString() but prefixed with @p title and formatted for printing.
    @param bitfield Field data. @param bytesize Field size in bytes. @param size Number of bits. @param title Heading text. @return Printable text. */
std::string PrintBitFieldString(const char* bitfield, uint32 bytesize, uint32 size, const char* title);

/*! @} */


//////////////////////////////////////////////////////////////
//                        Threading                         //
//////////////////////////////////////////////////////////////

/*! @name Threading and CPU statistics
    @{ */

/*! @brief Format the current call stack as printable text.
    @param startLine First stack frame to include (0 = top). @param endLine Last frame (0 = all).
    @return Multi-line backtrace text. @note Uses backtrace() on POSIX; symbol quality depends on build flags. */
std::string PrintProgramTrace(uint32 startLine = 0, uint32 endLine = 0);
/*! @brief Capture the current call stack. @return One string per stack frame, top first. */
std::list<std::string> GetProgramTrace();

/*! @brief Atomically increment a 32-bit value. @param v Value to modify. @return The new (incremented) value. */
int32 AtomicIncrement32(int32 volatile &v);
/*! @brief Atomically increment a 64-bit value. @param v Value to modify. @return The new value. */
int64 AtomicIncrement64(int64 volatile &v);
/*! @brief Atomically decrement a 32-bit value. @param v Value to modify. @return The new value. */
int32 AtomicDecrement32(int32 volatile &v);
/*! @brief Atomically decrement a 64-bit value. @param v Value to modify. @return The new value. */
int64 AtomicDecrement64(int64 volatile &v);

/*! @brief Suspend the calling thread. @param ms Sleep duration in milliseconds. @return true on success. */
bool Sleep(uint32 ms);

/*! @brief Start a new OS thread.
    @param func Entry point (THREAD_FUNCTION signature; platform calling convention hidden by the macros above).
    @param args Opaque pointer passed to @p func.
    @param[out] thread Receives the thread handle.
    @param[out] osID Receives the OS thread id.
    @return true when the thread was created. */
bool CreateThread(THREAD_FUNCTION func, void* args, ThreadHandle& thread, uint32 &osID);

/*! @brief Join a thread. @param hThread Thread handle. @param timeoutMS Max wait in ms (0 = wait forever). @return true when the thread finished. */
bool WaitForThreadToFinish(ThreadHandle hThread, uint32 timeoutMS = 0);
bool ReapThread(ThreadHandle& hThread);
bool TryReapThread(ThreadHandle& hThread);

/*! @brief Non-blocking check whether a thread has terminated. @param hThread Thread handle. @return true when finished. */
bool CheckForThreadFinished(ThreadHandle hThread);

/*! @brief Forcibly kill a thread. @param hThread Thread handle. @return true on success.
    @note Last resort only: locks and heap state held by the thread stay corrupted/leaked. */
bool TerminateThread(ThreadHandle hThread);

/*! @brief Suspend a thread's execution. @param hThread Thread handle. @return true on success.
    @note Windows: SuspendThread; POSIX: signal-based, may not be supported everywhere. */
bool PauseThread(ThreadHandle hThread);

/*! @brief Resume a thread paused with PauseThread(). @param hThread Thread handle. @return true on success. */
bool ContinueThread(ThreadHandle hThread);

/*! @brief Get a process-unique id for the calling thread. @param[out] tid Receives the id. @return true on success. */
bool GetCurrentThreadUniqueID(uint32 &tid);

/*! @brief Get the OS-level id of the calling thread (gettid / GetCurrentThreadId). @param[out] tid Receives the id. @return true on success. */
bool GetCurrentThreadOSID(uint32 &tid);

/*! @brief Get the handle of the calling thread. @param[out] thread Receives the handle. @return true on success. */
bool GetCurrentThread(ThreadHandle& thread);

/*! @brief Check whether a thread is still alive. @param hThread Thread handle. @return true when running. */
bool IsThreadRunning(ThreadHandle hThread);

/*! @brief Report this platform's capability for per-thread CPU statistics collection.
    @return One of THREAD_STATS_OFF / THREAD_STATS_AUTO / THREAD_STATS_ADHOC. */
uint32 GetThreadStatColAbility();

#if defined	WINDOWS
	#define FileTimeToUint64(ft) (((uint64)(ft.dwHighDateTime))<<32)|((uint64)ft.dwLowDateTime)
#endif

/*! @brief Get accumulated CPU time of a specific thread.
    @param hThread Thread handle. @param[out] ticks Receives CPU time in microseconds.
    @return true on success. @note Cross-thread queries are Windows-only until pthreads exposes per-thread getrusage. */
bool GetCPUTicks(ThreadHandle hThread, uint64& ticks);

/*! @brief Get accumulated CPU time of the calling thread. @param[out] ticks Receives CPU time in microseconds. @return true on success. */
bool GetCPUTicks(uint64& ticks);

/*! @brief Get accumulated CPU time of the current process. @param[out] ticks Receives CPU time in microseconds. @return true on success. */
bool GetProcessCPUTicks(uint64& ticks);

/*! @brief Get accumulated CPU time of another process. @param osProcID OS process id. @param[out] ticks Receives CPU time in microseconds. @return true on success. */
bool GetProcessCPUTicks(uint32 osProcID, uint64& ticks);

/*! @brief Sample CPU usage of this process and of the whole OS since the previous call.
    @param[out] procPercentUse Process CPU usage in percent.
    @param[out] osPercentUse Total OS CPU usage in percent.
    @param[in,out] prevOSTicks Caller-kept previous total-OS tick counter.
    @param[in,out] prevOSIdleTicks Caller-kept previous idle tick counter.
    @param[in,out] prevProcTicks Caller-kept previous process tick counter.
    @return true on success. @note Pass the same three counters on every call; the first call establishes the baseline. */
bool GetProcAndOSCPUUsage(double& procPercentUse, double& osPercentUse, uint64 &prevOSTicks, uint64 &prevOSIdleTicks, uint64 &prevProcTicks);

/*! @brief As GetProcAndOSCPUUsage() above, but for an arbitrary process.
    @param osProcID OS process id.
    @param[out] procPercentUse Process CPU usage in percent.
    @param[out] osPercentUse Total OS CPU usage in percent.
    @param[in,out] prevOSTicks Caller-kept previous total-OS tick counter.
    @param[in,out] prevOSIdleTicks Caller-kept previous idle tick counter.
    @param[in,out] prevProcTicks Caller-kept previous process tick counter. */
bool GetProcAndOSCPUUsage(uint32 osProcID, double& procPercentUse, double& osPercentUse, uint64 &prevOSTicks, uint64 &prevOSIdleTicks, uint64 &prevProcTicks);

/*! @brief Get the instantaneous total OS CPU usage. @param[out] percentUse Usage in percent. @return true on success. */
bool GetOSCPUUsage(double& percentUse);

/*! @brief Query a thread's scheduling priority. @param hThread Thread handle. @param priority Receives/compares the CMSDK priority value. @return true on success. */
bool GetThreadPriority(ThreadHandle hThread, uint16 priority);

/*! @brief Set a thread's scheduling priority. @param hThread Thread handle. @param priority CMSDK priority value (converted via ToOSPriority()). @return true on success. */
bool SetThreadPriority(ThreadHandle hThread, uint16 priority);

/*! @brief Map a CMSDK priority value to the platform's native priority scale. @param pri CMSDK priority. @return OS priority. */
int ToOSPriority(int pri);

/*! @brief Map a native OS priority back to the CMSDK priority scale. @param pri OS priority. @return CMSDK priority. */
int FromOSPriority(int pri);

/*! @brief Send a signal to a thread (POSIX pthread_kill; limited emulation on Windows). @param hThread Thread handle. @param signal Signal number. @return true on success. */
bool SignalThread(ThreadHandle hThread, int32 signal);

/*! @} */

//////////////////////////////////////////////////////////////
//                       Desktop                            //
//////////////////////////////////////////////////////////////

/*! @name Desktop and console
    @{ */

/*! @brief Get the primary desktop resolution. @param[out] width Pixels. @param[out] height Pixels. @return true on success (false on headless systems). */
bool GetDesktopSize(uint32& width, uint32& height);

/*! @brief Set the console window title. @param name New title. @param prepend Prepend to the existing title instead of replacing it. @return true on success. @note Windows-only effect; no-op elsewhere. */
bool RenameConsoleWindow(const char* name, bool prepend = false);

/*! @brief Move/resize the console window. @param x,y Position (-1 = keep). @param w,h Size (-1 = keep). @return true on success. @note Windows-only effect. */
bool MoveConsoleWindow(int32 x = -1, int32 y = -1, int32 w = -1, int32 h = -1);

/*! @} */

//////////////////////////////////////////////////////////////
//                      Processes                           //
//////////////////////////////////////////////////////////////

#define PROC_ERROR		0
#define PROC_TERMINATED	1
#define PROC_NOTSTARTED	2
#define PROC_RUNNING	3
#define PROC_TIMEOUT	4

#define NUM_PIPES          2
#define PARENT_WRITE_PIPE  0
#define PARENT_READ_PIPE   1
/* always in a pipe[], pipe[0] is for read and 
	pipe[1] is for write */
#define READ_FD  0
#define WRITE_FD 1
#define PARENT_READ_FD  ( (*pipes)[PARENT_READ_PIPE][READ_FD]   )
#define PARENT_WRITE_FD ( (*pipes)[PARENT_WRITE_PIPE][WRITE_FD] )
#define CHILD_READ_FD   ( (*pipes)[PARENT_WRITE_PIPE][READ_FD]  )
#define CHILD_WRITE_FD  ( (*pipes)[PARENT_READ_PIPE][WRITE_FD]  )

#define PROCBUFSIZE 4096

/*! @name Process management
    @{ */

/*! @brief Run a command synchronously and capture its output.
    @param cmdline Command line to execute.
    @param initdir Working directory (NULL = inherit).
    @param timeout Max run time in milliseconds before the child is killed.
    @param[out] stdoutString Captured standard output.
    @param[out] stderrString Captured standard error.
    @return Child exit code, or a negative value on launch failure. */
int RunOSCommand(const char* cmdline, const char* initdir, uint32 timeout, std::string& stdoutString, std::string& stderrString);
/*! @brief Launch a detached child process.
    @param cmdline Command line. @param initdir Working directory (NULL = inherit). @param title Console title (Windows).
    @param x,y,w,h Initial console window geometry (-1 = default; Windows only).
    @return Process handle id for use with GetProcessStatus()/EndProcess()/WaitForProcess(), or 0 on failure. */
uint32 NewProcess(const char* cmdline, const char* initdir = NULL, const char* title = NULL,
				  int16 x = -1, int16 y = -1, int16 w = -1, int16 h = -1);
/*! @brief Poll a child started with NewProcess().
    @param proc Process id from NewProcess(). @param[out] returncode Exit code when terminated.
    @return One of PROC_ERROR / PROC_TERMINATED / PROC_NOTSTARTED / PROC_RUNNING. */
uint8 GetProcessStatus(uint32 proc, int &returncode);
/*! @brief Forcibly terminate a child process. @param proc Process id from NewProcess(). @return true on success. */
bool EndProcess(uint32 proc);

/*! @name Managed child launch (T1.4 external-executable support)
    Extended launch/lifecycle helpers used by ExternalExecManager. On POSIX these
    are thin conveniences; on Windows they carry the env block, working directory,
    optional stdout/stderr capture pipes and console-group/graceful-stop plumbing
    that plain NewProcess() does not.
    @{ */
/*! @brief Launch a child with environment overrides and optional output capture.
    @param cmdline Command line (already substituted). @param initdir Working directory (NULL/"" = inherit).
    @param title Console/space title. @param env Extra environment variables merged over the parent's (NULL = none).
    @param captureOutput true to redirect the child's stdout/stderr into pipes readable via ReadProcessOutput().
    @param ignoreOutput true to send the child's stdout/stderr to the null device (ignored unless captureOutput is false).
    @param newProcessGroup true to start the child in its own process group so it can be sent a graceful console
           break via SendProcessBreak() independently of the parent (recommended for graceful stop).
    @return Process id for GetProcessStatus()/EndProcess()/ReadProcessOutput()/SendProcessBreak(), or 0 on failure. */
uint32 NewProcessEx(const char* cmdline, const char* initdir, const char* title,
					const std::map<std::string, std::string>* env,
					bool captureOutput, bool ignoreOutput, bool newProcessGroup);
/*! @brief Read any pending captured stdout/stderr from a child launched with captureOutput=true.
    Non-blocking. Appends raw bytes (may be partial lines) to the supplied strings.
    @param proc Process id. @param[out] out Appended stdout bytes. @param[out] err Appended stderr bytes.
    @return true if the process is known and its pipes were polled (even if nothing was read). */
bool ReadProcessOutput(uint32 proc, std::string& out, std::string& err);
/*! @brief Attempt a graceful stop: POSIX sends the given signal; Windows posts a CTRL_BREAK to the
    child's process group (requires newProcessGroup=true at launch) and falls back to nothing if unsupported.
    Callers should wait, then EndProcess() as the forceful fallback.
    @param proc Process id. @param sig POSIX signal number (ignored on Windows). @return true if the request was delivered. */
bool SendProcessBreak(uint32 proc, int sig);
/*! @} */
/*! @brief Wait for a child to exit.
    @param proc Process id. @param timeout Max wait in ms. @param[out] returncode Exit code.
    @return PROC_TERMINATED, PROC_TIMEOUT or PROC_ERROR. */
uint8 WaitForProcess(uint32 proc, uint32 timeout, int &returncode);
/*! @brief Get the OS process id of the current process. @return PID. */
uint32 GetLocalProcessID();

/*! @} */

//////////////////////////////////////////////////////////////
//                      DLL Libraries                       //
//////////////////////////////////////////////////////////////

#ifdef WINDOWS
	#define DLLHandle HINSTANCE
#else // WINDOWS
	#define DLLHandle void*
#endif // WINDOWS

/*! @name Dynamic libraries and command line
    @{ */

/*! @brief Signature of a plain function exported from a dynamically loaded library. */
typedef int (* LibraryFunction)();

class CommandLineInfo;
/*! @brief Singleton snapshot of the parsed process command line (set via SetCommandLine()).
    Splits argv into the executable path/name, positional items and key=value arguments. */
class CommandLineInfo {
public:
	static CommandLineInfo* CommandLineInfoSingleton;
	CommandLineInfo() {}
	std::string CommandLineString;
	std::string CommandLineExec;
	std::string CommandLineExecOnly;
	std::string CommandLineExecPath;
	std::vector<std::string> CommandLineItems;
	std::map<std::string, std::string> CommandLineArgs;
};



/*! @brief Parse and store the process command line for later retrieval by the Get/HasCommandLine* functions.
    @param argc Argument count from main(). @param argv Argument vector from main().
    @return true on success. @note Call once early in main(). */
bool SetCommandLine(int argc, char* argv[]);
/*! @brief Get the full original command line as one string. @return Command line text. */
std::string GetCommandLine();
/*! @brief Get the directory portion of the executable path. @return Path (platform separators). */
std::string GetCommandLinePath();
/*! @brief Get the full executable path as invoked. @return Path + filename. */
std::string GetCommandLineExecutable();
/*! @brief Get just the executable filename without path. @return Filename. */
std::string GetCommandLineExecutableOnly();
/*! @brief Number of positional command line items (excluding the executable). @return Count. */
uint32 GetCommandLineArgCount();
/*! @brief Get the n-th positional command line item. @param n Zero-based index. @return Item text, or empty when out of range. */
std::string GetCommandLineArg(uint16 n);
/*! @brief Get the value of a 'key=value' command line argument.
    @param key Argument name (case as given). @return Value, or empty string when absent.
    @note Inserts an empty entry into the map on miss; use HasCommandLineArg() to test without side effects. */
std::string GetCommandLineArg(const char* key);
/*! @brief Test for a 'key=value' argument without mutating the argument map.
    @param key Argument name. @param[out] value Receives the value when present.
    @return true if the key was given on the command line. */
bool HasCommandLineArg(const char* key, std::string& value);

/*! @brief Thin RAII wrapper around a dynamically loaded library (LoadLibrary / dlopen). */
class Library {
public:
	/*! @brief Normalize a library name into a platform filename (adds lib prefix / .dll, .so, .dylib suffix and optional path).
	    @param filename Base library name. @param path Optional directory. @return Full platform-specific filename. */
	static std::string patchLibraryFilename(const char* filename, const char* path = NULL);

	Library();
	~Library();
	/*! @brief Load a library. @param filename Library file (see patchLibraryFilename()). @return true on success. */
	bool load(const char* filename);
	/*! @brief Resolve an exported function. @param funcName Symbol name. @return Function pointer or NULL. */
	LibraryFunction getFunction(const char* funcName);
private:
	DLLHandle handle;
};

/*! @brief Load a library by name, applying platform filename conventions. @param libName Base name. @return Heap-allocated Library (caller owns) or NULL on failure. */
Library* OpenLibrary(const char* libName);

/*! @} */

/*! @name OS and hardware information
    @{ */

/*! @brief Get this machine's hostname. @return Pointer to an internal static buffer; do not free. */
const char* GetComputerName();

/*! @brief Current resident memory usage of this process. @return Bytes. */
uint64 GetProcessMemoryUsage();
/*! @brief Peak resident memory usage of this process. @return Bytes. */
uint64 GetPeakProcessMemoryUsage();

/*! @brief Number of logical CPU cores. @return Core count. */
uint16 GetCPUCount();

/*! @brief CPU architecture id. @return One of OSCPU_X86 / OSCPU_AMD64 / OSCPU_IA64 / OSCPU_UNKNOWN. */
uint16 GetCPUArchitecture();

/*! @brief Nominal CPU clock speed. @return Hz (approximate; read from OS info). */
uint64 GetCPUSpeed();

/*! @brief Total physical RAM installed. @return Bytes. */
uint64 GetSystemMemorySize();

/*! @brief Query total and free physical memory. @param[out] totalRAM Bytes. @param[out] freeRAM Bytes. @return true on success. */
bool GetSystemMemoryUsage(uint64 &totalRAM, uint64 &freeRAM);

/*! @brief Architecture name string, e.g. "x86_64". @return Pointer to an internal static buffer. */
const char* GetSystemArchitecture();

/*! @brief OS name string, e.g. "Windows", "Linux", "Darwin". @return Pointer to an internal static buffer. */
const char* GetSystemOSName();

/*! @brief Detailed OS version.
    @param[out] major,minor,build Version numbers.
    @param[out] text Buffer receiving a descriptive string. @param textSize Size of @p text.
    @return true on success. */
bool GetSystemOSVersion(uint16& major, uint16& minor, uint16& build, char* text, uint16 textSize);

/*! @} */

//bool RunOSTextCommand(const char* cmd, char* result, uint32 size);

//extern char OSLocalHostName[1024];
//extern char OSArchitectureName[1024];
//extern char OSName[1024];


//////////////////////////////////////////////////////////////
//                         Sockets                          //
//////////////////////////////////////////////////////////////

/*! @name Sockets and networking
    Thin portability layer over BSD sockets / Winsock. On non-Windows builds
    SOCKET is a plain int and closesocket() maps to close(); CHECKNETWORKINIT
    expands to a Winsock WSAStartup guard on Windows and to nothing elsewhere.
    @{ */

#ifdef WINDOWS
	/*! @brief Ensure WSAStartup has been called (Windows only). @return true when the network stack is ready. */
	bool CheckNetworkInit();
	#define CHECKNETWORKINIT utils::CheckNetworkInit();
#else
	#define CHECKNETWORKINIT
	#define WSAEWOULDBLOCK EAGAIN
#endif

/*! @brief Translate a socket error code into text and classify it.
    @param wsaError Error number (WSAGetLastError()/errno).
    @param[out] errorString Buffer for the message. @param errorStringMaxSize Buffer size.
    @param[out] isRecoverable Set true for transient errors (e.g. would-block) where a retry makes sense.
    @return true when the code was recognized. */
bool GetSocketError(int wsaError, char* errorString, uint16 errorStringMaxSize, bool* isRecoverable);

/*! @brief Get the last OS error number (errno / GetLastError()). @return Error code. */
int GetLastOSErrorNumber();
/*! @brief Get the last OS error as human-readable text. @return Message string. */
std::string GetLastOSErrorMessage();

/*! @brief Wait until a socket has data to read. @param s Socket. @param timeout Max wait in ms (negative = infinite). @return true when readable. */
bool WaitForSocketReadability(SOCKET s, int32 timeout);
/*! @brief Wait until a socket can be written without blocking. @param s Socket. @param timeout Max wait in ms. @return true when writable. */
bool WaitForSocketWriteability(SOCKET s, int32 timeout);

/*! @brief Put a socket into non-blocking mode. @param s Socket. @return true on success. */
bool SetSocketNonBlockingMode(SOCKET s);
/*! @brief Put a socket into blocking mode. @param s Socket. @return true on success. */
bool SetSocketBlockingMode(SOCKET s);

/*! @brief Description of one local network interface (IPv4 address, MAC and names). */
struct NetworkInterfaces {
	uint32 address;
	uint64 mac;
	char name[MAXKEYNAMELEN+1];
	char friendlyName[MAXKEYNAMELEN+1];
};

/*! @brief Resolve a hostname to an IPv4 address. @param name Hostname or dotted quad. @param[out] address Address in network byte order. @return true on success. */
bool LookupIPAddress(const char* name, uint32& address);
/*! @brief Reverse-resolve an IPv4 address to a hostname. @param address Address (network byte order). @param[out] name Buffer. @param maxSize Buffer size. @return true on success. */
bool LookupHostname(uint32 address, char* name, uint32 maxSize);
/*! @brief Local hostname as std::string. @return Hostname. */
std::string GetLocalHostnameString();
/*! @brief Local hostname into a caller buffer. @param[out] name Buffer. @param maxSize Buffer size. @return true on success. */
bool GetLocalHostname(char* name, uint32 maxSize);
/*! @brief Test whether a textual address refers to this machine (loopback or a local interface). @param addr Hostname or dotted quad. @return true when local. */
bool IsLocalIPAddress(const char* addr);
/*! @brief Test whether a numeric IPv4 address is local. @param address Address (network byte order). @return true when local. */
bool IsLocalIPAddress(uint32& address);
/*! @brief Get the primary local IPv4 address. @param[out] address Address (network byte order). @return true on success. */
bool GetLocalIPAddress(uint32& address);
/*! @brief List all local IPv4 addresses. @param[out] count Number of entries. @return malloc'ed array (caller frees) or NULL. */
uint32* GetLocalIPAddresses(uint32& count);
/*! @brief Get the primary local MAC address. @param[out] address 48-bit MAC in the low bytes. @return true on success. */
bool GetLocalMACAddress(uint64& address);
/*! @brief List all local MAC addresses. @param[out] count Number of entries. @return malloc'ed array (caller frees) or NULL. */
uint64* GetLocalMACAddresses(uint32& count);
/*! @brief Enumerate local network interfaces with address, MAC and names. @param[out] count Number of entries. @return malloc'ed array (caller frees) or NULL. */
NetworkInterfaces* GetLocalInterfaces(uint32& count);
/*! @brief Find the next free TCP port above @p lastPort. @param lastPort Port to start after. @param[out] nextPort Receives the available port. @return true when one was found. */
bool GetNextAvailableLocalPort(uint16 lastPort, uint16 &nextPort);

#define LOCALHOSTIP 16777343 // 127.0.0.1 as 32-bit dec
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))

#define GETIPPORT(a) *(uint16*)((char*)&a + sizeof(uint32))
#define GETIPADDRESS(a) *(uint32*)&a
#define GETIPADDRESSPORT(a,p) (((uint32)a)) | (((uint64)p)<<32)
#define GETIPADDRESSQUAD(a) ((uint8*)&a)[0], ((uint8*)&a)[1], ((uint8*)&a)[2], ((uint8*)&a)[3]
#define GETIPADDRESSQUADPORT(a) ((uint8*)&a)[0], ((uint8*)&a)[1], ((uint8*)&a)[2], ((uint8*)&a)[3], ((uint16*)&a)[2]

/*! @} */

/*! @name Registry access (Windows; no-ops/defaults elsewhere)
    Keys are given as full paths, e.g. "HKEY_LOCAL_MACHINE\\Software\\...".
    On non-Windows platforms these functions return failure/empty values.
    @{ */

#ifdef WINDOWS
	/*! @brief Split a registry path into root handle + subkey (Windows only). @param key Full key path. @param[out] hKeyRoot Receives the root HKEY. @return Subkey portion. */
	std::string GetRegistryKeyInfo(const char* key, HKEY &hKeyRoot);
	/*! @brief Like GetRegistryKeyInfo() but for the parent of @p key (Windows only). */
	std::string GetRegistryParentKeyInfo(const char* key, HKEY &hKeyRoot);
#endif // WINDOWS
/*! @brief Read a 32-bit registry value. @param key Full key path. @param entry Value name. @return Value, or ERROR32 on failure. */
uint32 ReadRegistryDWORD(const char* key, const char* entry);
/*! @brief Read a 64-bit registry value. @param key Full key path. @param entry Value name. @return Value, or ERROR64 on failure. */
uint64 ReadRegistryQWORD(const char* key, const char* entry);
/*! @brief Read a string registry value. @param key Full key path. @param entry Value name. @return Value, or empty string on failure. */
std::string ReadRegistryString(const char* key, const char* entry);
/*! @brief Write a 32-bit registry value (creates the key when needed). @return true on success. */
bool WriteRegistryDWORD(const char* key, const char* entry, uint32 value);
/*! @brief Write a 64-bit registry value. @return true on success. */
bool WriteRegistryQWORD(const char* key, const char* entry, uint64 value);
/*! @brief Write a string registry value. @return true on success. */
bool WriteRegistryString(const char* key, const char* entry, const char* value);
/*! @brief Delete a single value from a key. @return true on success. */
bool DeleteRegistryEntry(const char* key, const char* entry);
/*! @brief Delete a (leaf) registry key. @return true on success. */
bool DeleteRegistryKey(const char* key);
/*! @brief Recursively delete a key and all subkeys. @param root Root key path. @param key Subtree to delete. @return true on success. */
bool DeleteRegistryTree(const char* root, const char* key);
//bool CopyRegistryKey(const char* key, const char* newName);
/*! @brief Recursively copy a registry subtree. @param entry Source subtree. @param newName Destination name. @return true on success. */
bool CopyRegistryTree(const char* entry, const char* newName);
//bool RenameRegistryKey(const char* key, const char* newName);
//bool RenameRegistryTree(const char* entry, const char* newName);



/*! @} */

/*! @name C-string helpers
    Low-level, allocation-free operations on raw char buffers.
    @{ */

/*! @brief Run the built-in self test of the utils module (duplicate declaration). @return true on success. */
bool UtilsTest();
/*! @brief Hex/decimal dump a memory region to stdout for debugging. @param p Data. @param size Bytes. @param asInt Print as integers instead of hex bytes. @param title Heading. */
void PrintBinary(void* p, uint32 size, bool asInt, const char* title);
/*! @brief Case-insensitive strstr. @param str Haystack. @param substr Needle. @param len Max haystack bytes to scan (0 = until NUL). @return Pointer to match within @p str, or NULL. */
const char* stristr(const char *str, const char *substr, uint32 len = 0);
/*! @brief Find the end of the current line.
    @param str Text. @param size Bytes available. @param[out] len Line length excluding the terminator. @param[out] crSize Terminator size (1 for \\n, 2 for \\r\\n).
    @return true when a line terminator was found. */
bool GetNextLineEnd(const char *str, uint32 size, uint32& len, uint32& crSize);
/*! @brief Replace every occurrence of a character, in place. @param str Buffer. @param size Bytes to scan. @param find Character to replace. @param replace Replacement. @return Number of replacements. */
uint32 TextReplaceCharsInPlace(char* str, uint32 size, char find, char replace);
/*! @brief Test whether @p str ends with @p end. @param str Text. @param end Suffix. @param caseSensitive Compare case-sensitively when true. @return true on match. */
bool TextEndsWith(const char* str, const char* end, bool caseSensitive = true);
/*! @brief Test whether @p str starts with @p start. @param str Text. @param start Prefix. @param caseSensitive Compare case-sensitively when true. @return true on match. */
bool TextStartsWith(const char* str, const char* start, bool caseSensitive = true);
/*! @brief Bounded strcpy that always NUL-terminates.
    @param dst Destination buffer. @param src Source. @param maxlen Destination capacity.
    @param copyAvailable When true, copy as much as fits; when false, copy nothing unless the whole string fits.
    @return Number of bytes copied (excluding NUL). */
uint32 strcpyavail(char* dst, const char* src, uint32 maxlen, bool copyAvailable);
/*! @brief Find the last occurrence of @p str2 in @p str1. @return Pointer to the last match, or NULL. */
const char* laststrstr(const char* str1, const char* str2);
/*! @brief Case-insensitive laststrstr(). @return Pointer to the last match, or NULL. */
const char* laststristr(const char* str1, const char* str2);

/*! @} */

/*! @name String replacement and templating
    @{ */

/*! @brief Replace occurrences of @p key with @p value in @p text.
    @param[in,out] text Text to modify. @param key Search string. @param value Replacement. @param onlyFirst Stop after the first replacement.
    @return Number of replacements performed. */
uint32 StringSingleReplace(std::string& text, std::string key, std::string value, bool onlyFirst);
/*! @brief Apply many key→value replacements in one pass. @param[in,out] text Text to modify. @param map Search/replace pairs. @param onlyFirst Replace only the first hit per key. @return Total replacements. */
uint32 StringMultiReplace(std::string& text, std::map<std::string, std::string>& map, bool onlyFirst);
/*! @brief Expand a named repeating template block in @p text once per map in @p list, substituting each map's keys inside the block.
    @param[in,out] text Template text. @param name Block name marker. @param list One map of substitutions per repetition.
    @return Number of substitutions performed. */
uint32 StringScriptReplace(std::string& text, std::string name, std::list< std::map<std::string, std::string> >& list);

/*! @} */

/*! @name Text case, trimming, splitting and joining
    All functions return new std::string values and leave inputs untouched.
    NULL inputs are treated as empty strings unless noted.
    @{ */

/*! @brief Capitalise the first letter of @p text. @param text Input. @return New string. */
std::string TextCapitalise(const char* text);
/*! @brief Convert to upper case (ASCII/current locale). @param text Input. @return New string. */
std::string TextUppercase(const char* text);
/*! @brief Convert to lower case (ASCII/current locale). @param text Input. @return New string. */
std::string TextLowercase(const char* text);
/*! @brief Prefix every line of @p text with @p indent. @param text Input. @param indent Indent string (e.g. "\t"). @return New string. */
std::string TextIndent(const char* text, const char* indent);
/*! @brief Remove one level of leading indentation from every line. @param text Input. @return New string. */
std::string TextUnindent(const char* text);
/*! @brief Strip a single pair of surrounding quotes if present. @param text Input. @return New string. */
std::string TextTrimQuotes(const char* text);
/*! @brief Strip leading and trailing whitespace. @param text Input. @return New string.
    @note "Whitespace" here means every character with a value of 32 or below,
    so control characters (tabs, CR/LF, NUL-adjacent bytes) are trimmed too.
    NULL input yields an empty string. */
std::string TextTrim(const char* text);
/*! @brief Split "k=v<sep>k=v..." text into a multimap (duplicate keys preserved).
    @param text Input. @param outersplit Separator between pairs. @param innersplit Separator between key and value. @return Parsed multimap.
    @note Keys and values are TextTrim()med. Segments that contain no
    @p innersplit before the next @p outersplit are silently skipped.
    @warning The scanner advances only one character past each @p outersplit
    match and takes the value from one character after the @p innersplit
    match, so both separators should be single characters; multi-character
    separators leave their remaining characters in the parsed fields. */
std::multimap<std::string, std::string> TextMultiMapSplit(const char* text, const char* outersplit, const char* innersplit);
/*! @brief Split "k=v<sep>k=v..." text into a map (later duplicates overwrite earlier ones).
    @param text Input. @param outersplit Separator between pairs. @param innersplit Separator between key and value. @return Parsed map.
    @note Same trimming, skipping and single-character-separator caveats as
    TextMultiMapSplit().
    @code
    std::map<std::string, std::string> m =
        utils::TextMapSplit("host=10.0.0.1; port=8080; port=9090", ";", "=");
    // m["host"] == "10.0.0.1", m["port"] == "9090" (last duplicate wins)
    @endcode */
std::map<std::string, std::string> TextMapSplit(const char* text, const char* outersplit, const char* innersplit);
/*! @brief Join vector elements with @p split. @param list Elements. @param split Separator. @param start First index. @param count Elements to join (0 = all remaining). @return Joined string. */
std::string TextJoin(std::vector<std::string> &list, const char* split, uint32 start = 0, uint32 count = 0);
/*! @brief Join list elements with @p split. @param list Elements. @param split Separator. @param start First index. @param count Elements to join (0 = all remaining). @return Joined string. */
std::string TextJoin(std::list<std::string> &list, const char* split, uint32 start = 0, uint32 count = 0);
/*! @brief Join a map as "key<innersplit>value<outersplit>..." with optional quoting.
    @param map Pairs. @param innersplit Key/value separator. @param outersplit Pair separator. @param keyquotes Quote keys. @param valquotes Quote values. @return Joined string. */
std::string TextJoin(std::map<std::string, std::string> &map, const char* innersplit, const char* outersplit, bool keyquotes, bool valquotes);
/*! @brief Serialize a map as a JSON object (keys/values escaped). @param map Pairs. @return JSON text. */
std::string TextJoinJSON(std::map<std::string, std::string> &map);
/*! @brief Serialize a map as XML, one @p innernodeName element per pair inside an @p outernodeName element. @return XML text. */
std::string TextJoinXML(std::map<std::string, std::string> &map, const char* innernodeName, const char* outernodeName);
/*! @brief Split text on a separator.
    @param text Input. @param split Separator string. @param keepEmpty Keep zero-length fields. @param autoTrim Trim whitespace from each field.
    @return Fields in order.
    @code
    std::vector<std::string> parts = TextListSplit("a, b,,c", ",", false, true); // {"a","b","c"}
    @endcode */
std::vector<std::string> TextListSplit(const char* text, const char* split, bool keepEmpty = true, bool autoTrim = false);
/*! @brief Split text into lines, handling both \\n and \\r\\n. @param text Input. @param keepEmpty Keep empty lines. @param autoTrim Trim each line. @return Lines in order. */
std::vector<std::string> TextListSplitLines(const char* text, bool keepEmpty = true, bool autoTrim = false);
/*! @brief Word-wrap text into lines no longer than @p maxLineLength. @param text Input. @param maxLineLength Max characters per line. @return Wrapped lines. */
std::vector<std::string> TextListBreakLines(const char* text, uint32 maxLineLength = 80);
/*! @brief Word-wrap text, joining the wrapped lines with @p breakstr. @param text Input. @param maxLineLength Max characters per line. @param breakstr Line separator to insert. @return Wrapped text. */
std::string TextListBreakLines(const char* text, uint32 maxLineLength, const char* breakstr);
/*! @brief Concatenate vector entries with @p sep. @param vect Entries to join. @param sep Separator. @param allowEmpty Include empty entries when true. @return Joined string. */
std::string TextVectorConcat(std::vector<std::string>, const char* sep, bool allowEmpty = true);
/*! @brief Split a command line into arguments, honouring quoting rules. @param cmdline Raw command line. @return Argument vector. */
std::vector<std::string> TextCommandlineSplit(const char* cmdline);
/*! @brief Split a command line into a malloc'ed argv array. @param cmdline Raw command line. @param[out] argc Argument count. @return argv array; free with DeleteCommandline(). */
char** SplitCommandline(const char* cmdline, int& argc);
/*! @brief Wide-character variant of SplitCommandline() (for Windows APIs). @param cmdline Raw command line. @param[out] argc Argument count. @return Wide argv array. */
wchar_t** SplitCommandlineW(const char* cmdline, int& argc);
/*! @brief Free an argv array produced by SplitCommandline(). @param argv Array. @param argc Count. @return true on success. */
bool DeleteCommandline(char** argv, int argc);

/*! @} */

/*! @name printf-style string formatting
    @{ */

/*! @brief printf into a std::string. @param format printf format string followed by varargs. @return Formatted text.
    Formats into a heap buffer sized to fit, so arbitrarily long results are
    safe (unlike fixed-size snprintf patterns). An empty format string, or a
    formatting failure, yields an empty string.
    @warning The usual varargs rules apply: pass c_str() for std::string
    arguments and make integer argument widths match the format specifier
    (use %lld/%llu style specifiers for 64-bit values).
    @code std::string s = StringFormat("%u items in %.2f s", n, secs); @endcode */
std::string StringFormat(const char *format, ...);
/*! @brief printf into a freshly allocated buffer. @param[out] size Receives the text length. @param format printf format + varargs. @return new[]-allocated buffer (caller deletes). */
char* StringFormat(uint32& size, const char *format, ...);
/*! @brief printf into a caller-supplied buffer with truncation. @param dst Destination. @param maxsize Capacity. @param format printf format + varargs. @return true when it fit. */
bool StringFormatInto(char* dst, uint32 maxsize, const char *format, ...);
/*! @brief va_list core used by the other StringFormat overloads. @param[out] size Receives the length. @param format printf format. @param args Variadic arguments. @return Allocated buffer (caller deletes). */
char* StringFormatVA(uint32& size, const char *format, va_list args);

/*! @} */

/*! @name Numeric conversion and checksums
    @{ */

/*! @brief Parse two hex digits into a byte. @param str Pointer to at least two hex characters. @return Byte value. */
unsigned char Hex2Char(const char* str);
/*! @brief Parse up to three decimal digits into a byte. @param str Decimal text. @return Byte value. */
unsigned char Dec2Char(const char* str);
/*! @brief Compute (or continue) a CRC-32 checksum.
    @param addr Data. @param length Bytes. @param crc Previous CRC to continue from (0 to start fresh).
    @return Updated CRC value.
    @note Bitwise implementation using the reflected ZIP/IEEE-802.3 polynomial,
    but @b without the standard 0xFFFFFFFF pre-conditioning and final XOR, so
    the value differs from zlib's crc32()/PKZIP for the same input. Use it
    only for CMSDK-internal integrity checks where both sides call this
    function. To checksum streamed data, feed each chunk in sequence, passing
    the previous return value as @p crc. */
int CRC32(const char *addr, uint32 length, int32 crc = 0);

/*! @brief Compare two doubles with epsilon tolerance. @param a,b Values. @return -1 when a<b, 0 when approximately equal, 1 when a>b. */
int8 CompareFloats(float64 a, float64 b);

/*! @} */

/*! @name File system
    Paths accept the platform's native separator; most functions also tolerate
    '/' on Windows. Directory listing uses dirent (via direntwin.h on Windows).
    @{ */

/*! @brief Existence, type, permission and timestamp information for one file, as returned by GetFileDetails(). */
struct FileDetails {
	bool doesExist;
	bool isDirectory;
	bool isReadable;
	bool isWritable;
	bool isExecutable;

	uint32 size;
	uint64 lastAccessTime;
	uint64 lastModifyTime;
	uint64 creationTime;
};

#define NOSUCHFILE		0
#define STANDARDFILE	1
#define STANDARDDIR		2

/*! @brief Read an entire file into a std::string. @param filename Path. @return File contents, or empty string when unreadable (indistinguishable from an empty file).
    @note Opens in text mode; on Windows CRLF pairs are collapsed to \\n.
    Binary data containing NUL bytes is not preserved reliably — use
    ReadAFile() with @p binary=true instead. */
std::string ReadAFileString(std::string filename);
/*! @brief Read an entire file into a new buffer.
    @param filename Path. @param[out] length Bytes read. @param binary Open in binary mode (no newline translation on Windows).
    @return new[]-allocated, NUL-terminated buffer (caller deletes) or NULL.
    @note The buffer is allocated one byte larger than the file and always
    NUL-terminated, so text reads can be used directly as C strings. In text
    mode on Windows, @p length is the byte count after CRLF translation and
    may be smaller than the on-disk size. Empty or unreadable files return
    NULL (with @p length = 0) — an empty file is not distinguishable from a
    missing one; call DoesAFileExist() first when that matters.
    @code
    uint32 len = 0;
    char* xml = utils::ReadAFile("config.xml", len);
    if (xml) {
        parse(xml, len);
        delete [] xml;   // caller owns the buffer
    }
    @endcode */
char* ReadAFile(const char* filename, uint32& length, bool binary = false);
/*! @brief Read @p dir/@p filename into a new buffer; see ReadAFile(). @return Allocated buffer or NULL. */
char* ReadAFile(const char* dir, const char* filename, uint32& length, bool binary = false);
/*! @brief Write (create/overwrite) a file. @param filename Path. @param data Bytes. @param length Byte count. @param binary Binary mode. @return true on success.
    @note Truncates any existing file — there is no append or atomic-replace
    behaviour (see AppendToAFile() for appending). Pass @p binary=true for
    non-text payloads, otherwise Windows expands \\n to CRLF on disk. */
bool WriteAFile(const char* filename, const char* data, uint32 length, bool binary = false);
/*! @brief Write @p dir/@p filename; see WriteAFile(). @return true on success. */
bool WriteAFile(const char* dir, const char* filename, const char* data, uint32 length, bool binary = false);
/*! @brief Append to a file, creating it if missing. @param filename Path. @param data Bytes. @param length Byte count. @param binary Binary mode. @return true on success. */
bool AppendToAFile(const char* filename, const char* data, uint32 length, bool binary = false);
/*! @brief Append to @p dir/@p filename; see AppendToAFile(). @return true on success. */
bool AppendToAFile(const char* dir, const char* filename, const char* data, uint32 length, bool binary = false);
/*! @brief List files in a directory matching an extension.
    @param dirname Directory. @param ext Extension filter (NULL/empty = all). @param[out] count Number of names.
    @param fullpath Prepend the directory to each name. @param maxNameLen Fixed per-name slot size in the returned block.
    @return Single allocated block of @p count zero-padded name slots each @p maxNameLen bytes (caller frees), or NULL.
    @note The result is not an array of pointers: entry @c i starts at
    @c buffer+i*maxNameLen and is a NUL-terminated string within its fixed
    slot. Names longer than @p maxNameLen-1 are truncated. Ordering follows
    the OS directory enumeration (not sorted).
    @code
    uint32 n = 0;
    char* names = utils::GetFileList("./logs", "txt", n, true);
    for (uint32 i = 0; i < n; i++)
        printf("%s\n", names + i*256);   // default maxNameLen = 256
    free(names);
    @endcode */
char* GetFileList(const char* dirname, const char* ext, uint32& count, bool fullpath, uint32 maxNameLen = 256);
/*! @brief Stat a file. @param filename Path. @return FileDetails; check doesExist first. */
FileDetails GetFileDetails(const char* filename);
/*! @brief Directory portion of a path. @param filename Path. @return Directory (without the trailing name). */
std::string GetFilePath(const char* filename);
/*! @brief Filename portion of a path. @param filename Path. @return Pointer into @p filename after the last separator. */
const char* GetFileBasename(const char* filename);
/*! @brief Current working directory. @return Absolute path. */
std::string GetCurrentDir();
/*! @brief Delete a file. @param filename Path. @param force Clear read-only attribute first when needed. @return true on success. */
bool DeleteAFile(const char* filename, bool force);
/*! @brief Delete @p dir/@p filename; see DeleteAFile(). @return true on success. */
bool DeleteAFile(const char* dir, const char* filename, bool force);
/*! @brief Delete a directory (recursively when @p force). @param dirname Path. @param force Delete non-empty directories. @return true on success. */
bool DeleteADir(const char* dirname, bool force);
/*! @brief Create a directory (parents included where supported). @param dirname Path. @return true on success or when it already exists. */
bool CreateADir(const char* dirname);
/*! @brief Test whether a directory exists. @param dirname Path. @return true when present and a directory. */
bool DoesADirExist(const char* dirname);
/*! @brief Test whether a regular file exists. @param filename Path. @return true when present. */
bool DoesAFileExist(const char* filename);
/*! @brief Delete all files inside a directory, leaving the directory itself. @param dirname Path. @param force Clear read-only attributes as needed. @return true on success. */
bool DeleteFilesInADir(const char* dirname, bool force);
/*! @brief Change read/write permission attributes of a file. @param filename Path. @param read Allow reading. @param write Allow writing. @return true on success. */
bool ChangeAFileAttr(const char* filename, bool read, bool write);
/*! @brief Move/rename a file. @param oldfilename Source. @param newfilename Destination. @param force Overwrite an existing destination. @return true on success. */
bool MoveAFile(const char* oldfilename, const char* newfilename, bool force = false);
/*! @brief Move a file between directories; see MoveAFile(). @return true on success. */
bool MoveAFile(const char* olddir, const char* oldfilename, const char* newdir, const char* newfilename, bool force = false);
/*! @brief Copy a file. @param oldfilename Source. @param newfilename Destination. @param force Overwrite an existing destination. @return true on success. */
bool CopyAFile(const char* oldfilename, const char* newfilename, bool force = false);
/*! @brief Copy a file between directories; see CopyAFile(). @return true on success. */
bool CopyAFile(const char* olddir, const char* oldfilename, const char* newdir, const char* newfilename, bool force = false);

/*! @} */

/*! @name ASCII ↔ number conversion
    The Ascii2* parsers operate on a substring [start,end) of the input; end=0
    means "until NUL". They skip surrounding whitespace and never throw.
    @note Common behaviour of the Ascii2Int64/Uint64/Int32/Uint32/Float64
    family: NULL input, start>end or entirely non-numeric text all yield 0,
    which is indistinguishable from a legitimate parsed zero — call
    IsTextNumeric() first when validity matters. Parsing is strtoll/strtod
    based, so leading whitespace is skipped, parsing stops at the first
    non-numeric character, and out-of-range values saturate to the type's
    min/max without an error indication. When end!=0 a temporary substring
    copy is allocated internally; the end=0 form is allocation-free.
    Ascii2Float64 always parses with '.' as the decimal point regardless of
    the process locale.
    @{ */

/*! @brief Render a signed integer as text in an arbitrary base. @param value Number. @param result Destination buffer. @param size Buffer capacity. @param base Radix 2–36. @return @p result, or NULL when it does not fit. */
char* Int2Ascii(int64 value, char* result, uint16 size, uint8 base);
/*! @brief Render an unsigned integer as text in an arbitrary base. @param value Number. @param result Destination buffer. @param size Buffer capacity. @param base Radix 2–36. @return @p result, or NULL when it does not fit. */
char* Uint2Ascii(uint64 value, char* result, uint16 size, uint8 base);
/*! @brief Convert 8-bit ASCII text to UTF-16LE (used for Windows wide APIs and some protocols).
    @param ascii Input text. @param len Input length in bytes. @param[out] size Output size in bytes.
    @return Allocated UTF-16LE buffer (caller frees). @note Bytes are widened as Latin-1; no multi-byte decoding. */
unsigned char* Ascii2UTF16LE(const char* ascii, uint32 len, uint32& size);

/*! @brief Test whether a (sub)string is a valid number. @param ascii Text. @param start First index. @param end One past last index (0 = NUL). @return true when numeric. */
bool IsTextNumeric(const char* ascii, uint32 start = 0, uint32 end = 0);
/*! @brief Parse a signed 64-bit decimal integer from a substring. @param ascii Text. @param start,end Substring bounds (end=0 ⇒ NUL). @return Parsed value; 0 when not numeric. */
int64 Ascii2Int64(const char* ascii, uint32 start = 0, uint32 end = 0);
/*! @brief Parse an unsigned 64-bit decimal integer from a substring. @return Parsed value; 0 when not numeric. */
uint64 Ascii2Uint64(const char* ascii, uint32 start = 0, uint32 end = 0);
/*! @brief Parse an unsigned 64-bit hexadecimal integer (with or without 0x) from a substring. @return Parsed value. */
uint64 AsciiHex2Uint64(const char* ascii, uint32 start = 0, uint32 end = 0);
/*! @brief Parse a signed 32-bit decimal integer from a substring. @return Parsed value; 0 when not numeric. */
int32 Ascii2Int32(const char* ascii, uint32 start = 0, uint32 end = 0);
/*! @brief Parse an unsigned 32-bit decimal integer from a substring. @return Parsed value; 0 when not numeric. */
uint32 Ascii2Uint32(const char* ascii, uint32 start = 0, uint32 end = 0);
/*! @brief Parse an unsigned 32-bit hexadecimal integer from a substring. @return Parsed value. */
uint32 AsciiHex2Uint32(const char* ascii, uint32 start = 0, uint32 end = 0);
/*! @brief Parse a 64-bit float from a substring (decimal point, not locale dependent). @return Parsed value; 0.0 when not numeric. */
float64 Ascii2Float64(const char* ascii, uint32 start = 0, uint32 end = 0);

/*! @brief Copy the substring [start,end) into a new NUL-terminated buffer. @param ascii Source. @param start,end Bounds. @return new[]-allocated copy (caller deletes). */
char* TextSubstringCopy(const char* ascii, uint32 start, uint32 end);

/*! @brief Unescape a JSON string value (\\\" \\\\ \\n \\t \\uXXXX etc.). @param str Escaped text (without surrounding quotes). @return Decoded text.
    @warning \\uXXXX sequences are decoded by truncating the code point to a
    single 8-bit char, so only U+0000..U+00FF survive; anything higher is
    mangled (no UTF-8 expansion, no surrogate-pair handling). A malformed
    trailing escape (e.g. a \\u with fewer than four digits at end of input)
    advances past the string end — only feed well-formed JSON string content. */
std::string DecodeJSON(std::string str);
/*! @brief Escape text for embedding as a JSON string value. @param str Raw text. @return Escaped text (without surrounding quotes).
    @note Bytes are escaped individually; multi-byte UTF-8 sequences pass
    through unmodified (which is valid JSON). The caller adds the surrounding
    double quotes. */
std::string EncodeJSON(std::string str);

/*! @} */

/*! @name Random numbers and human-readable sizes
    @{ */

/*! @brief Seed the pseudo-random generator. @param seedvalue Seed; 0 = derive from current time. @return true on success.
    @note Wraps the C library srand(), i.e. one global generator shared by
    the whole process — seeding affects every user of rand()/RandomValue().
    Seed once at startup; reseeding repeatedly (e.g. per call) destroys the
    distribution. Not suitable for cryptographic purposes. */
bool SeedRandomValues(uint32 seedvalue = 0);
/*! @brief Uniform random double in [0,1). @return Random value.
    @note Combines three rand() calls to obtain far more resolution than a
    single RAND_MAX (important on Windows where RAND_MAX is only 32767).
    Uses the global C rand() state: results interleave across threads and
    the sequence is only reproducible in single-threaded use after
    SeedRandomValues() with a fixed seed. */
double RandomValue();
/*! @brief Uniform random double in [0,@p to). @param to Upper bound. @return Random value. */
double RandomValue(double to);
/*! @brief Uniform random double in [@p from,@p to). @return Random value. */
double RandomValue(double from, double to);
/*! @brief Uniform random double in [@p from,@p to) quantized to multiples of @p interval. @return Random value. */
double RandomValue(double from, double to, double interval);
/*! @brief Uniform random integer in [@p from,@p to]. @return Random value. */
int64 RandomInt(int64 from = 0, int64 to = 100);

/*! @brief Format a byte count with binary units, e.g. 1536 → "1.5 KB". @param val Byte count. @return Human-readable text.
    @note Units are binary (1 KB = 1024 B) with two decimals, and the unit
    switches at 512 of the current unit (so 600000 renders as "585.94 KB",
    not "0.57 MB"). Intended for logs/UI — not parseable back losslessly. */
std::string BytifySize(double val);
/*! @brief Format two byte counts as "x / y" with matching units. @param val1,val2 Byte counts. @return Human-readable text. */
std::string BytifySizes(double val1, double val2);
/*! @brief Format a byte rate, e.g. "1.5 KB/s". @param val Bytes per second. @return Human-readable text. */
std::string BytifyRate(double val);
/*! @brief Format two byte rates as "x / y" with matching units. @param val1,val2 Bytes per second. @return Human-readable text. */
std::string BytifyRates(double val1, double val2);

/*! @} */

/** @} */ // end of utils

} // namespace utils
} // namespace cmlabs

#endif //_UTILS_H_

