#pragma once

// ------------------------------------------------------------------------------------------------
#include "Core/Common.hpp"

// ------------------------------------------------------------------------------------------------
#include "Library/IO/Buffer.hpp"
#include "Library/Numeric/Long.hpp"

// ------------------------------------------------------------------------------------------------
#include <vector>

// ------------------------------------------------------------------------------------------------
#include <maxminddb.h>

// ------------------------------------------------------------------------------------------------
namespace SqMod {

/* ------------------------------------------------------------------------------------------------
 * Handle validation.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    #define SQMOD_VALIDATE(x)               (x).Validate(__FILE__, __LINE__)
    #define SQMOD_GET_VALID(x)              (x).GetValid(__FILE__, __LINE__)
    #define SQMOD_GET_VALID_ELEM(x)         (x).GetValidElem(__FILE__, __LINE__)
    #define SQMOD_GET_VALID_DATA(x)         (x).GetValidData(__FILE__, __LINE__)
#else
    #define SQMOD_VALIDATE(x)               (x).Validate()
    #define SQMOD_GET_VALID(x)              (x).GetValid()
    #define SQMOD_GET_VALID_ELEM(x)         (x).GetValidElem()
    #define SQMOD_GET_VALID_DATA(x)         (x).GetValidData()
#endif // _DEBUG

/* ------------------------------------------------------------------------------------------------
 * Forward declarations.
*/
class Database;
class Metadata;
class Description;
class SockAddr;
class EntryData;
class EntryDataList;
class LookupResult;
class SearchNode;

/* ------------------------------------------------------------------------------------------------
 * Forward handle declarations.
*/
struct DbHnd;

/* ------------------------------------------------------------------------------------------------
 * Common typedefs.
*/
typedef SharedPtr< DbHnd > DbRef;

/* ------------------------------------------------------------------------------------------------
 * Used to retrieve the string representation of the specified type identifier.
*/
const SQChar * AsTypeStr(uint32_t id);

/* ------------------------------------------------------------------------------------------------
 * Retrieve the value from the specified entry data as a boolean.
*/
bool GetEntryAsBool(const MMDB_entry_data_s & ed);

/* ------------------------------------------------------------------------------------------------
 * Retrieve the value from the specified entry data as a native integer.
*/
SQInteger GetEntryAsInteger(const MMDB_entry_data_s & ed);

/* ------------------------------------------------------------------------------------------------
 * Retrieve the value from the specified entry data as a floating point.
*/
SQFloat GetEntryAsFloat(const MMDB_entry_data_s & ed);

/* ------------------------------------------------------------------------------------------------
 * Retrieve the value from the specified entry data as a long integer.
*/
LightObj GetEntryAsLong(const MMDB_entry_data_s & ed);

/* ------------------------------------------------------------------------------------------------
 * Retrieve the value from the specified entry data as a string.
*/
LightObj GetEntryAsString(const MMDB_entry_data_s & ed);

/* ------------------------------------------------------------------------------------------------
 * Retrieve the value from the specified entry data as a stream of bytes.
*/
LightObj GetEntryAsBytes(const MMDB_entry_data_s & ed);

/* ------------------------------------------------------------------------------------------------
 * Class that can obtain information from string addresses and be used repeatedly thereafter.
*/
class SockAddr
{
public:

    // --------------------------------------------------------------------------------------------
    typedef struct addrinfo Type; // The managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type*           Pointer; // Pointer to the managed type.
    typedef const Type*     ConstPtr; // Constant pointer to the managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type&           Reference; // Reference to the managed type.
    typedef const Type&     ConstRef; // Constant reference to the managed type.

protected:

    /* --------------------------------------------------------------------------------------------
     * Validate the managed sockaddr pointer and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    void Validate(const SQChar * file, int32_t line) const;
#else
    void Validate() const;
#endif // _DEBUG

    /* --------------------------------------------------------------------------------------------
     * Validate the managed sockaddr pointer and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    SQMOD_NODISCARD Pointer GetValid(const SQChar * file, int32_t line) const;
#else
    SQMOD_NODISCARD Pointer GetValid() const;
#endif // _DEBUG

private:

    // ---------------------------------------------------------------------------------------------
    Pointer m_Handle; // The managed sockaddr structure.
    String  m_Addres; // The address that was queried for information.

public:

    /* --------------------------------------------------------------------------------------------
     * Default constructor.
    */
    SockAddr()
        : m_Handle(nullptr)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Base constructor.
    */
    explicit SockAddr(const SQChar * addr);

    /* --------------------------------------------------------------------------------------------
     * Copy constructor. (disabled)
    */
    SockAddr(const SockAddr & o) = delete;

    /* --------------------------------------------------------------------------------------------
     * Move constructor.
    */
    SockAddr(SockAddr && o) noexcept
        : m_Handle(o.m_Handle)
        , m_Addres(std::move(o.m_Addres))
    {
        o.m_Handle = nullptr;
    }

    /* --------------------------------------------------------------------------------------------
     * Destructor.
    */
    ~SockAddr();

    /* --------------------------------------------------------------------------------------------
     * Copy assignment operator. (disabled)
    */
    SockAddr & operator = (const SockAddr & o) = delete;

    /* --------------------------------------------------------------------------------------------
     * Move assignment operator.
    */
    SockAddr & operator = (SockAddr && o) noexcept
    {
        if (m_Handle != o.m_Handle)
        {
            m_Handle = o.m_Handle;
            m_Addres = o.m_Addres;
            o.m_Handle = nullptr;
        }
        return *this;
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the internal addrinfo structure pointer.
    */
    Pointer GetHandle()
    {
        return m_Handle;
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the internal addrinfo structure pointer.
    */
    SQMOD_NODISCARD Pointer GetHandle() const
    {
        return m_Handle;
    }

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to convert an instance of this type to a string.
    */
    SQMOD_NODISCARD const String & ToString() const
    {
        return m_Addres;
    }

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to retrieve the name from instances of this type.
    */
    static SQInteger Typename(HSQUIRRELVM vm);

    /* --------------------------------------------------------------------------------------------
     * See whether this instance references a valid addrinfo structure.
    */
    SQMOD_NODISCARD bool IsValid() const
    {
        return m_Handle;
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the associated string address.
    */
    SQMOD_NODISCARD const String & GetAddress() const
    {
        return m_Addres;
    }
};

/* ------------------------------------------------------------------------------------------------
 * Manages a reference counted database instance.
*/
class DbHnd
{
    // --------------------------------------------------------------------------------------------
    friend class Database;

public:

    // --------------------------------------------------------------------------------------------
    typedef MMDB_s          Type; // The managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type*           Pointer; // Pointer to the managed type.
    typedef const Type*     ConstPtr; // Constant pointer to the managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type&           Reference; // Reference to the managed type.
    typedef const Type&     ConstRef; // Constant reference to the managed type.

public:

    // --------------------------------------------------------------------------------------------
    MMDB_s     mDb; // The managed database handle.

    /* --------------------------------------------------------------------------------------------
     * Default constructor.
    */
    DbHnd(const SQChar * filepath, uint32_t flags);

    /* --------------------------------------------------------------------------------------------
     * Copy constructor. (disabled)
    */
    DbHnd(const DbHnd & o) = delete;

    /* --------------------------------------------------------------------------------------------
     * Move constructor. (disabled)
    */
    DbHnd(DbHnd && o) = delete;

    /* --------------------------------------------------------------------------------------------
     * Destructor.
    */
    ~DbHnd();

    /* --------------------------------------------------------------------------------------------
     * Copy assignment operator. (disabled)
    */
    DbHnd & operator = (const DbHnd & o) = delete;

    /* --------------------------------------------------------------------------------------------
     * Move assignment operator. (disabled)
    */
    DbHnd & operator = (DbHnd && o) = delete;
};

/* ------------------------------------------------------------------------------------------------
 * Class that can be used to open and query information from MaxMind database files.
*/
class Database
{
public:

    // --------------------------------------------------------------------------------------------
    typedef DbHnd::Type             Type; // The managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type*                   Pointer; // Pointer to the managed type.
    typedef const Type*             ConstPtr; // Constant pointer to the managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type&                   Reference; // Reference to the managed type.
    typedef const Type&             ConstRef; // Constant reference to the managed type.

protected:

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    void Validate(const SQChar * file, int32_t line) const;
#else
    void Validate() const;
#endif //

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    SQMOD_NODISCARD const DbRef & GetValid(const SQChar * file, int32_t line) const;
#else
    SQMOD_NODISCARD const DbRef & GetValid() const;
#endif // _DEBUG

private:

    // ---------------------------------------------------------------------------------------------
    DbRef m_Handle; // The managed database handle.

public:

    /* --------------------------------------------------------------------------------------------
     * Default constructor. (null)
    */
    Database()
        : m_Handle()
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Base constructor. (default flags)
    */
    explicit Database(StackStrF & filepath)
        : m_Handle(new DbHnd(filepath.mPtr, 0))
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Base constructor.
    */
    Database(uint32_t flags, StackStrF & filepath)
        : m_Handle(new DbHnd(filepath.mPtr, flags))
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Explicit handle constructor.
    */
    explicit Database(const DbRef & db) // NOLINT(modernize-pass-by-value)
        : m_Handle(db)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Copy constructor.
    */
    Database(const Database & o) = default;

    /* --------------------------------------------------------------------------------------------
     * Move constructor.
    */
    Database(Database && o) = default;

    /* --------------------------------------------------------------------------------------------
     * Copy assignment operator.
    */
    Database & operator = (const Database & o) = default;

    /* --------------------------------------------------------------------------------------------
     * Move assignment operator.
    */
    Database & operator = (Database && o) = default;

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to convert an instance of this type to a string.
    */
    SQMOD_NODISCARD const SQChar * ToString() const
    {
        return m_Handle ? m_Handle->mDb.filename : _SC("");
    }

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to retrieve the name from instances of this type.
    */
    static SQInteger Typename(HSQUIRRELVM vm);

    /* --------------------------------------------------------------------------------------------
     * See whether this instance references a valid database instance.
    */
    SQMOD_NODISCARD bool IsValid() const
    {
        return m_Handle;
    }

    /* --------------------------------------------------------------------------------------------
     * Release the manages handles/pointers and become a null instance.
    */
    void Release()
    {
        m_Handle.Reset();
    }

    /* --------------------------------------------------------------------------------------------
     * Return the number of active references to the managed database instance.
    */
    SQMOD_NODISCARD uint32_t GetRefCount() const
    {
        return m_Handle.Count();
    }

    /* --------------------------------------------------------------------------------------------
     * Attempt to open the specified database.
    */
    void Open(const SQChar * filepath)
    {
        Open(filepath, 0);
    }

    /* --------------------------------------------------------------------------------------------
     * Attempt to open the specified database.
    */
    void Open(const SQChar * filepath, uint32_t flags)
    {
        // Make sure there isn't another database handle
        if (!m_Handle)
        {
            m_Handle = DbRef(new DbHnd(filepath, flags));
        }
        else
        {
            STHROWF("Loading is disabled while database is referenced");
        }
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the metadata associated with the managed database handle.
    */
    SQMOD_NODISCARD Metadata GetMetadata() const;

    /* --------------------------------------------------------------------------------------------
     * Retrieve the metadata associated with the managed database handle as an entry data list.
    */
    SQMOD_NODISCARD LightObj GetMetadataAsEntryDataList() const;

    /* --------------------------------------------------------------------------------------------
     * Look up an IP address that is passed in as a null-terminated string.
    */
    LookupResult LookupString(const SQChar * addr);

    /* --------------------------------------------------------------------------------------------
     * Looks up an IP address that has already been resolved by getaddrinfo().
    */
    LookupResult LookupSockAddr(SockAddr & sockaddr);

    /* --------------------------------------------------------------------------------------------
     * Retrieve a specific node from the managed database.
    */
    SQMOD_NODISCARD SearchNode ReadNode(uint32_t node) const;
};

/* ------------------------------------------------------------------------------------------------
 * Class that can hold and be used inspect meta-data descriptions.
*/
class Description
{
public:

    // --------------------------------------------------------------------------------------------
    typedef MMDB_description_s      Type; // The managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type*                   Pointer; // Pointer to the managed type.
    typedef const Type*             ConstPtr; // Constant pointer to the managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type&                   Reference; // Reference to the managed type.
    typedef const Type&             ConstRef; // Constant reference to the managed type.

protected:

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    void Validate(const SQChar * file, int32_t line) const;
#else
    void Validate() const;
#endif // _DEBUG

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and description pointer and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    SQMOD_NODISCARD Pointer GetValid(const SQChar * file, int32_t line) const;
#else
    SQMOD_NODISCARD Pointer GetValid() const;
#endif // _DEBUG

private:

    // ---------------------------------------------------------------------------------------------
    DbRef   m_Handle; // The database associated with this meta-data description.
    Pointer m_Description; // The inspected meta-data description structure.

public:

    /* --------------------------------------------------------------------------------------------
     * Default constructor. (null)
    */
    Description()
        : m_Handle(), m_Description(nullptr)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Construct and with a specific meta-data description.
    */
    Description(const DbRef & db, Pointer description) // NOLINT(modernize-pass-by-value)
        : m_Handle(db), m_Description(description)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Copy constructor.
    */
    Description(const Description &) = default;

    /* --------------------------------------------------------------------------------------------
     * Move constructor.
    */
    Description(Description &&) = default;

    /* --------------------------------------------------------------------------------------------
     * Copy assignment operator.
    */
    Description & operator = (const Description &) = default;

    /* --------------------------------------------------------------------------------------------
     * Move assignment operator.
    */
    Description & operator = (Description &&) = default;

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to convert an instance of this type to a string.
    */
    SQMOD_NODISCARD const SQChar * ToString() const
    {
        return m_Description ? m_Description->description : _SC("");
    }

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to retrieve the name from instances of this type.
    */
    static SQInteger Typename(HSQUIRRELVM vm);

    /* --------------------------------------------------------------------------------------------
     * See whether this instance references a valid database and description structure.
    */
    SQMOD_NODISCARD bool IsValid() const
    {
        return m_Handle; // If there's a database handle then there's a description too
    }

    /* --------------------------------------------------------------------------------------------
     * Release the manages handles/pointers and become a null instance.
    */
    void Release()
    {
        m_Handle.Reset();
        m_Description = nullptr;
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the database associated with the managed handle/pointer.
    */
    SQMOD_NODISCARD Database GetDatabase() const;

    /* --------------------------------------------------------------------------------------------
     * Return the number of active references to the managed database instance.
    */
    SQMOD_NODISCARD uint32_t GetRefCount() const
    {
        return m_Handle.Count();
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value of the managed description handle.
    */
    SQMOD_NODISCARD const SQChar * GetDescriptionValue() const
    {
        return SQMOD_GET_VALID(*this)->description;
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the language of the managed description handle.
    */
    SQMOD_NODISCARD const SQChar * GetDescriptionLanguage() const
    {
        return SQMOD_GET_VALID(*this)->language;
    }
};

/* ------------------------------------------------------------------------------------------------
 * Class that can hold and be used to inspect entry data values.
*/
class EntryData
{
public:

    // --------------------------------------------------------------------------------------------
    typedef MMDB_entry_data_s       Type; // The managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type*                   Pointer; // Pointer to the managed type.
    typedef const Type*             ConstPtr; // Constant pointer to the managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type&                   Reference; // Reference to the managed type.
    typedef const Type&             ConstRef; // Constant reference to the managed type.

protected:

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    void Validate(const SQChar * file, int32_t line) const;
#else
    void Validate() const;
#endif // _DEBUG

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    SQMOD_NODISCARD ConstRef GetValid(const SQChar * file, int32_t line) const;
#else
    SQMOD_NODISCARD ConstRef GetValid() const;
#endif // _DEBUG

private:

    // ---------------------------------------------------------------------------------------------
    DbRef   m_Handle; // The database from which this result comes from.
    Type    m_Entry; // The managed entry-data structure.

public:

    /* --------------------------------------------------------------------------------------------
     * Default constructor. (null)
    */
    EntryData();

    /* --------------------------------------------------------------------------------------------
     * Construct and take ownership of a certain entry data.
    */
    EntryData(const DbRef & db, Reference entry) // NOLINT(modernize-pass-by-value)
        : m_Handle(db), m_Entry(entry)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Copy constructor.
    */
    EntryData(const EntryData &) = default;

    /* --------------------------------------------------------------------------------------------
     * Move constructor.
    */
    EntryData(EntryData &&) = default;

    /* --------------------------------------------------------------------------------------------
     * Copy assignment operator.
    */
    EntryData & operator = (const EntryData &) = default;

    /* --------------------------------------------------------------------------------------------
     * Move assignment operator.
    */
    EntryData & operator = (EntryData &&) = default;

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to convert an instance of this type to a string.
    */
    SQMOD_NODISCARD const SQChar * ToString() const
    {
        return AsTypeStr(m_Entry.type);
    }

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to retrieve the name from instances of this type.
    */
    static SQInteger Typename(HSQUIRRELVM vm);

    /* --------------------------------------------------------------------------------------------
     * See whether this instance references a valid database and entry structure.
    */
    SQMOD_NODISCARD bool IsValid() const
    {
        return m_Handle && m_Entry.has_data;
    }

    /* --------------------------------------------------------------------------------------------
     * Release the manages handles/pointers and become a null instance.
    */
    void Release();

    /* --------------------------------------------------------------------------------------------
     * Retrieve the database associated with the managed handle/pointer.
    */
    SQMOD_NODISCARD Database GetDatabase() const;

    /* --------------------------------------------------------------------------------------------
     * Return the number of active references to the managed database instance.
    */
    SQMOD_NODISCARD uint32_t GetRefCount() const
    {
        return m_Handle.Count();
    }

    /* --------------------------------------------------------------------------------------------
     * Used to retrieve the type of the current element as a string.
    */
    SQMOD_NODISCARD const SQChar * TypeName() const
    {
        // Validate the handle
        SQMOD_VALIDATE(*this);
        // Return the requested information
        return AsTypeStr(m_Entry.type);
    }

    /* --------------------------------------------------------------------------------------------
     * See whether a valid element is currently processed.
    */
    SQMOD_NODISCARD bool HasData() const
    {
        return ConvTo< bool >::From(SQMOD_GET_VALID(*this).has_data);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the type identifier of the current element.
    */
    SQMOD_NODISCARD SQInteger GetType() const
    {
        return ConvTo< SQInteger >::From(SQMOD_GET_VALID(*this).type);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the offset of the current element.
    */
    SQMOD_NODISCARD SQInteger GetOffset() const
    {
        return ConvTo< SQInteger >::From(SQMOD_GET_VALID(*this).offset);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the offset of the next element.
    */
    SQMOD_NODISCARD SQInteger DataSize() const
    {
        return ConvTo< SQInteger >::From(SQMOD_GET_VALID(*this).data_size);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value from the current element as a boolean.
    */
    SQMOD_NODISCARD bool GetBool() const
    {
        return GetEntryAsBool(SQMOD_GET_VALID(*this));
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value from the current element as a native integer.
    */
    SQMOD_NODISCARD SQInteger GetInteger() const
    {
        return GetEntryAsInteger(SQMOD_GET_VALID(*this));
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value from the current element as a floating point.
    */
    SQMOD_NODISCARD SQFloat GetFloat() const
    {
        return GetEntryAsFloat(SQMOD_GET_VALID(*this));
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value from the current element as a long integer.
    */
    SQMOD_NODISCARD LightObj GetLong() const
    {
        return GetEntryAsLong(SQMOD_GET_VALID(*this));
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value from the current element as a string.
    */
    SQMOD_NODISCARD LightObj GetString() const
    {
        return GetEntryAsString(SQMOD_GET_VALID(*this));
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value from the current element as a stream of bytes.
    */
    SQMOD_NODISCARD LightObj GetBytes() const
    {
        return GetEntryAsBytes(SQMOD_GET_VALID(*this));
    }
};

/* ------------------------------------------------------------------------------------------------
 * Class that can hold and be used inspect database meta-data.
*/
class EntryDataList
{
public:

    // --------------------------------------------------------------------------------------------
    typedef MMDB_entry_data_list_s  Type; // The managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type*                   Pointer; // Pointer to the managed type.
    typedef const Type*             ConstPtr; // Constant pointer to the managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type&                   Reference; // Reference to the managed type.
    typedef const Type&             ConstRef; // Constant reference to the managed type.

protected:

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    void Validate(const SQChar * file, int32_t line) const;
#else
    void Validate() const;
#endif // _DEBUG

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    SQMOD_NODISCARD Pointer GetValid(const SQChar * file, int32_t line) const;
#else
    SQMOD_NODISCARD Pointer GetValid() const;
#endif // _DEBUG

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    SQMOD_NODISCARD Pointer GetValidElem(const SQChar * file, int32_t line) const;
#else
    SQMOD_NODISCARD Pointer GetValidElem() const;
#endif // _DEBUG

private:

    // ---------------------------------------------------------------------------------------------
    DbRef   m_Handle; // The database associated with this meta-data.
    Pointer m_List; // The managed entry data list.
    Pointer m_Elem; // The currently processed element from the list.

public:

    /* --------------------------------------------------------------------------------------------
     * Construct and with a specific entry list.
    */
    EntryDataList(const DbRef & db, Pointer list) // NOLINT(modernize-pass-by-value)
        : m_Handle(db), m_List(list), m_Elem(list)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Default constructor. (null)
    */
    EntryDataList()
        : m_Handle(), m_List(nullptr), m_Elem(nullptr)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Copy constructor. (disabled)
    */
    EntryDataList(const EntryDataList &) = delete;

    /* --------------------------------------------------------------------------------------------
     * Move constructor.
    */
    EntryDataList(EntryDataList && o)
 noexcept         : m_Handle(std::move(o.m_Handle))
        , m_List(o.m_List)
        , m_Elem(o.m_Elem)
    {
        o.m_List = nullptr;
        o.m_Elem = nullptr;
    }

    /* --------------------------------------------------------------------------------------------
     * Destructor.
    */
    ~EntryDataList()
    {
        // Do we have to free any list?
        if (m_List)
        {
            MMDB_free_entry_data_list(m_List);
        }
    }

    /* --------------------------------------------------------------------------------------------
     * Copy assignment operator. (disabled)
    */
    EntryDataList & operator = (const EntryDataList &) = delete;

    /* --------------------------------------------------------------------------------------------
     * Move assignment operator.
    */
    EntryDataList & operator = (EntryDataList && o) noexcept
    {
        if (m_List != o.m_List)
        {
            m_Handle = std::move(o.m_Handle);
            m_List = o.m_List;
            m_Elem = o.m_Elem;
            o.m_List = nullptr;
            o.m_Elem = nullptr;
        }
        return *this;
    }

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to convert an instance of this type to a string.
    */
    SQMOD_NODISCARD const SQChar * ToString() const
    {
        return m_Elem ? AsTypeStr(m_Elem->entry_data.type) : _SC("invalid");
    }

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to retrieve the name from instances of this type.
    */
    static SQInteger Typename(HSQUIRRELVM vm);

    /* --------------------------------------------------------------------------------------------
     * See whether this instance references a valid database and element pointer.
    */
    SQMOD_NODISCARD bool IsValid() const
    {
        return m_Handle && m_Elem;
    }

    /* --------------------------------------------------------------------------------------------
     * Release the manages handles/pointers and become a null instance.
    */
    void Release()
    {
        m_Handle.Reset();
        // Do we have to free any list?
        if (m_List)
        {
            MMDB_free_entry_data_list(m_List);
        }
        // Finally, release those as well
        m_List = nullptr;
        m_Elem = nullptr;
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the database associated with the managed handle/pointer.
    */
    SQMOD_NODISCARD Database GetDatabase() const;

    /* --------------------------------------------------------------------------------------------
     * Return the number of active references to the managed database instance.
    */
    SQMOD_NODISCARD uint32_t GetRefCount() const
    {
        return m_Handle.Count();
    }

    /* --------------------------------------------------------------------------------------------
     * See whether a valid element is currently processed.
    */
    SQMOD_NODISCARD bool HaveElement() const
    {
        return m_Elem;
    }

    /* --------------------------------------------------------------------------------------------
     * Used to retrieve the type of the current element as a string.
    */
    SQMOD_NODISCARD const SQChar * TypeName() const
    {
        return AsTypeStr(SQMOD_GET_VALID_ELEM(*this)->entry_data.type);
    }

    /* --------------------------------------------------------------------------------------------
     * Return the total entries in the list.
    */
    SQMOD_NODISCARD uint32_t GetCount() const;

    /* --------------------------------------------------------------------------------------------
     * Go to the next element.
    */
    bool Next();

    /* --------------------------------------------------------------------------------------------
     * Advance a certain number of elements.
    */
    bool Advance(SQInteger n);

    /* --------------------------------------------------------------------------------------------
     * Go back to the first element in the list.
    */
    void Reset()
    {
        m_Elem = SQMOD_GET_VALID_ELEM(*this);
    }

    /* --------------------------------------------------------------------------------------------
     * See whether a valid element is currently processed.
    */
    SQMOD_NODISCARD bool HasData() const
    {
        return ConvTo< bool >::From(SQMOD_GET_VALID_ELEM(*this)->entry_data.has_data);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the type identifier of the current element.
    */
    SQMOD_NODISCARD SQInteger GetType() const
    {
        return ConvTo< SQInteger >::From(SQMOD_GET_VALID_ELEM(*this)->entry_data.type);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the offset of the current element.
    */
    SQMOD_NODISCARD SQInteger GetOffset() const
    {
        return ConvTo< SQInteger >::From(SQMOD_GET_VALID_ELEM(*this)->entry_data.offset);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the offset of the next element.
    */
    SQMOD_NODISCARD SQInteger DataSize() const
    {
        return ConvTo< SQInteger >::From(SQMOD_GET_VALID_ELEM(*this)->entry_data.data_size);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value from the current element as a boolean.
    */
    SQMOD_NODISCARD bool GetBool() const
    {
        return GetEntryAsBool(SQMOD_GET_VALID_ELEM(*this)->entry_data);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value from the current element as a native integer.
    */
    SQMOD_NODISCARD SQInteger GetInteger() const
    {
        return GetEntryAsInteger(SQMOD_GET_VALID_ELEM(*this)->entry_data);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value from the current element as a floating point.
    */
    SQMOD_NODISCARD SQFloat GetFloat() const
    {
        return GetEntryAsFloat(SQMOD_GET_VALID_ELEM(*this)->entry_data);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value from the current element as a long integer.
    */
    SQMOD_NODISCARD LightObj GetLong() const
    {
        return GetEntryAsLong(SQMOD_GET_VALID_ELEM(*this)->entry_data);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value from the current element as a string.
    */
    SQMOD_NODISCARD LightObj GetString() const
    {
        return GetEntryAsString(SQMOD_GET_VALID_ELEM(*this)->entry_data);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the value from the current element as a stream of bytes.
    */
    SQMOD_NODISCARD LightObj GetBytes() const
    {
        return GetEntryAsBytes(SQMOD_GET_VALID_ELEM(*this)->entry_data);
    }

    /* --------------------------------------------------------------------------------------------
     * Dump the contents of the list to the specified list.
    */
    void DumpTo(const SQChar * filepath) const
    {
        DumpTo(filepath, 0);
    }

    /* --------------------------------------------------------------------------------------------
     * Dump the contents of the list to the specified list.
    */
    void DumpTo(const SQChar * filepath, int32_t indent) const;
};

/* ------------------------------------------------------------------------------------------------
 * Class that can hold and be used to work with lookup results.
*/
class LookupResult
{
public:

    // --------------------------------------------------------------------------------------------
    typedef MMDB_lookup_result_s    Type; // The managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type*                   Pointer; // Pointer to the managed type.
    typedef const Type*             ConstPtr; // Constant pointer to the managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type&                   Reference; // Reference to the managed type.
    typedef const Type&             ConstRef; // Constant reference to the managed type.

protected:

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    void Validate(const SQChar * file, int32_t line) const;
#else
    void Validate() const;
#endif // _DEBUG

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    SQMOD_NODISCARD const DbRef & GetValid(const SQChar * file, int32_t line) const;
#else
    SQMOD_NODISCARD const DbRef & GetValid() const;
#endif // _DEBUG

private:

    // ---------------------------------------------------------------------------------------------
    DbRef   m_Handle; // The database from which this result comes from.
    Type    m_Result; // The managed result structure.

public:

    /* --------------------------------------------------------------------------------------------
     * Default constructor. (null)
    */
    LookupResult();

    /* --------------------------------------------------------------------------------------------
     * Construct and take ownership of a certain result.
    */
    LookupResult(const DbRef & db, Reference result) // NOLINT(modernize-pass-by-value)
        : m_Handle(db), m_Result(result)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Copy constructor.
    */
    LookupResult(const LookupResult &) = default;

    /* --------------------------------------------------------------------------------------------
     * Move constructor.
    */
    LookupResult(LookupResult &&) = default;

    /* --------------------------------------------------------------------------------------------
     * Copy assignment operator.
    */
    LookupResult & operator = (const LookupResult &) = default;

    /* --------------------------------------------------------------------------------------------
     * Move assignment operator.
    */
    LookupResult & operator = (LookupResult &&) = default;

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to convert an instance of this type to a string.
    */
    SQMOD_NODISCARD String ToString() const
    {
        return fmt::format("{}", m_Result.entry.offset);
    }

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to retrieve the name from instances of this type.
    */
    static SQInteger Typename(HSQUIRRELVM vm);

    /* --------------------------------------------------------------------------------------------
     * See whether this instance references a valid database and result structure.
    */
    SQMOD_NODISCARD bool IsValid() const
    {
        return m_Handle && m_Result.found_entry;
    }

    /* --------------------------------------------------------------------------------------------
     * Release the manages handles/pointers and become a null instance.
    */
    void Release();

    /* --------------------------------------------------------------------------------------------
     * Retrieve the database associated with the managed handle/pointer.
    */
    SQMOD_NODISCARD Database GetDatabase() const;

    /* --------------------------------------------------------------------------------------------
     * Return the number of active references to the managed database instance.
    */
    SQMOD_NODISCARD uint32_t GetRefCount() const
    {
        return m_Handle.Count();
    }

    /* --------------------------------------------------------------------------------------------
     * See whether the result contains a valid entry in the associated database.
    */
    SQMOD_NODISCARD bool FoundEntry() const
    {
        // Validate the database handle
        SQMOD_VALIDATE(*this);
        // Return the requested information
        return m_Result.found_entry;
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the net-mask from the result structure.
    */
    SQMOD_NODISCARD SQInteger GetNetMask() const
    {
        // Validate the database handle
        SQMOD_VALIDATE(*this);
        // Return the requested information
        return static_cast< SQInteger >(m_Result.netmask);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the entire entry data list.
    */
    Object GetEntryDataList();

    /* --------------------------------------------------------------------------------------------
     * Lookup data in the associated result using the specified path.
    */
    SQMOD_NODISCARD static SQInteger GetValue(HSQUIRRELVM vm);
};

/* ------------------------------------------------------------------------------------------------
 * Class that can hold and be used inspect database meta-data.
*/
class Metadata
{
public:

    // --------------------------------------------------------------------------------------------
    typedef MMDB_metadata_s         Type; // The managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type*                   Pointer; // Pointer to the managed type.
    typedef const Type*             ConstPtr; // Constant pointer to the managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type&                   Reference; // Reference to the managed type.
    typedef const Type&             ConstRef; // Constant reference to the managed type.

protected:

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    void Validate(const SQChar * file, int32_t line) const;
#else
    void Validate() const;
#endif // _DEBUG

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    SQMOD_NODISCARD Pointer GetValid(const SQChar * file, int32_t line) const;
#else
    SQMOD_NODISCARD Pointer GetValid() const;
#endif // _DEBUG

private:

    // ---------------------------------------------------------------------------------------------
    DbRef   m_Handle; // The database associated with this meta-data.
    Pointer m_Metadata; // The inspected meta-data structure.

public:

    /* --------------------------------------------------------------------------------------------
     * Default constructor. (null)
    */
    Metadata()
        : m_Handle(), m_Metadata(nullptr)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Construct and with a specific meta-data.
    */
    Metadata(const DbRef & db, Pointer metadata) // NOLINT(modernize-pass-by-value)
        : m_Handle(db), m_Metadata(metadata)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Copy constructor.
    */
    Metadata(const Metadata &) = default;

    /* --------------------------------------------------------------------------------------------
     * Move constructor.
    */
    Metadata(Metadata &&) = default;

    /* --------------------------------------------------------------------------------------------
     * Copy assignment operator.
    */
    Metadata & operator = (const Metadata &) = default;

    /* --------------------------------------------------------------------------------------------
     * Move assignment operator.
    */
    Metadata & operator = (Metadata &&) = default;

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to convert an instance of this type to a string.
    */
    SQMOD_NODISCARD const SQChar * ToString() const
    {
        return m_Metadata ? m_Metadata->database_type : _SC("");
    }

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to retrieve the name from instances of this type.
    */
    static SQInteger Typename(HSQUIRRELVM vm);

    /* --------------------------------------------------------------------------------------------
     * See whether this instance references a valid database and meta-data pointer.
    */
    SQMOD_NODISCARD bool IsValid() const
    {
        return m_Handle; // If there's a database handle then there's a meta-data too
    }

    /* --------------------------------------------------------------------------------------------
     * Release the manages handles/pointers and become a null instance.
    */
    void Release()
    {
        m_Handle.Reset();
        m_Metadata = nullptr;
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the database associated with the managed handle/pointer.
    */
    SQMOD_NODISCARD Database GetDatabase() const;

    /* --------------------------------------------------------------------------------------------
     * Return the number of active references to the managed database instance.
    */
    SQMOD_NODISCARD uint32_t GetRefCount() const
    {
        return m_Handle.Count();
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the node count.
    */
    SQMOD_NODISCARD SQInteger GetNodeCount() const
    {
        return ConvTo< SQInteger >::From(SQMOD_GET_VALID(*this)->node_count);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the record size.
    */
    SQMOD_NODISCARD SQInteger GetRecordSize() const
    {
        return ConvTo< SQInteger >::From(SQMOD_GET_VALID(*this)->record_size);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the IP version.
    */
    SQMOD_NODISCARD SQInteger GetIpVersion() const
    {
        return ConvTo< SQInteger >::From(SQMOD_GET_VALID(*this)->ip_version);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the database type.
    */
    SQMOD_NODISCARD const SQChar * GetDatabaseType() const
    {
        return SQMOD_GET_VALID(*this)->database_type;
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the number of language names.
    */
    SQMOD_NODISCARD SQInteger GetLanguageCount() const
    {
        return ConvTo< SQInteger >::From(SQMOD_GET_VALID(*this)->languages.count);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the name of a certain language.
    */
    SQMOD_NODISCARD const SQChar * GetLanguageName(uint32_t idx) const
    {
        // Validate the specified index
        if (idx > SQMOD_GET_VALID(*this)->languages.count)
        {
            STHROWF("The specified language index is out of range: {} > {}", idx, m_Metadata->languages.count);
        }
        // Return the requested name
        return m_Metadata->languages.names[idx];
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the major version of the binary format.
    */
    SQMOD_NODISCARD SQInteger GetBinaryFormatMajorVersion() const
    {
        return ConvTo< SQInteger >::From(SQMOD_GET_VALID(*this)->binary_format_major_version);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the minor version of the binary format.
    */
    SQMOD_NODISCARD SQInteger GetBinaryFormatMinorVersion() const
    {
        return ConvTo< SQInteger >::From(SQMOD_GET_VALID(*this)->binary_format_minor_version);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the build epoch.
    */
    SQMOD_NODISCARD Object GetBuildEpoch() const
    {
        return Object(SqTypeIdentity< ULongInt >{}, SqVM(), ConvTo< uint64_t >::From(SQMOD_GET_VALID(*this)->build_epoch));
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the number of available description handles.
    */
    SQMOD_NODISCARD SQInteger GetDescriptionCount() const
    {
        return ConvTo< SQInteger >::From(SQMOD_GET_VALID(*this)->description.count);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the handle of a certain description.
    */
    SQMOD_NODISCARD Description GetDescriptionHandle(uint32_t idx) const;

    /* --------------------------------------------------------------------------------------------
     * Retrieve the description of a certain description handle.
    */
    SQMOD_NODISCARD const SQChar * GetDescriptionValue(uint32_t idx) const
    {
        // Validate the specified index
        if (idx > SQMOD_GET_VALID(*this)->description.count)
        {
            STHROWF("The specified description index is out of range: {} > {}", idx, m_Metadata->description.count);
        }
        // Return the requested description value
        return m_Metadata->description.descriptions[idx]->description;
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the language of a certain description handle.
    */
    SQMOD_NODISCARD const SQChar * GetDescriptionLanguage(uint32_t idx) const
    {
        // Validate the specified index
        if (idx > SQMOD_GET_VALID(*this)->description.count)
        {
            STHROWF("The specified description index is out of range: {} > {}", idx, m_Metadata->description.count);
        }
        // Return the requested description language
        return m_Metadata->description.descriptions[idx]->language;
    }
};

/* ------------------------------------------------------------------------------------------------
 * Class that can hold and be used to work with search nodes.
*/
class SearchNode
{
public:

    // --------------------------------------------------------------------------------------------
    typedef MMDB_search_node_s      Type; // The managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type*                   Pointer; // Pointer to the managed type.
    typedef const Type*             ConstPtr; // Constant pointer to the managed type.

    // --------------------------------------------------------------------------------------------
    typedef Type&                   Reference; // Reference to the managed type.
    typedef const Type&             ConstRef; // Constant reference to the managed type.

protected:

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    void Validate(const SQChar * file, int32_t line) const;
#else
    void Validate() const;
#endif // _DEBUG

    /* --------------------------------------------------------------------------------------------
     * Validate the managed database handle and throw an error if invalid.
    */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
    SQMOD_NODISCARD Reference GetValid(const SQChar * file, int32_t line);
#else
    SQMOD_NODISCARD Reference GetValid();
#endif // _DEBUG

private:

    // ---------------------------------------------------------------------------------------------
    DbRef   m_Handle; // The database from which this search node comes from.
    Type    m_Node; // The managed search node structure.

public:

    /* --------------------------------------------------------------------------------------------
     * Default constructor. (null)
    */
    SearchNode();

    /* --------------------------------------------------------------------------------------------
     * Construct and take ownership of a certain search node.
    */
    SearchNode(const DbRef & db, Reference node) // NOLINT(modernize-pass-by-value)
        : m_Handle(db), m_Node(node)
    {
        /* ... */
    }

    /* --------------------------------------------------------------------------------------------
     * Copy constructor.
    */
    SearchNode(const SearchNode &) = default;

    /* --------------------------------------------------------------------------------------------
     * Move constructor.
    */
    SearchNode(SearchNode &&) = default;

    /* --------------------------------------------------------------------------------------------
     * Copy assignment operator.
    */
    SearchNode & operator = (const SearchNode &) = default;

    /* --------------------------------------------------------------------------------------------
     * Move assignment operator.
    */
    SearchNode & operator = (SearchNode &&) = default;

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to convert an instance of this type to a string.
    */
    SQMOD_NODISCARD String ToString() const
    {
        return fmt::format("<{}:{},{}:{}>", m_Node.left_record, AsTypeStr(m_Node.left_record_type)
                                        , m_Node.right_record, AsTypeStr(m_Node.right_record_type));
    }

    /* --------------------------------------------------------------------------------------------
     * Used by the script engine to retrieve the name from instances of this type.
    */
    static SQInteger Typename(HSQUIRRELVM vm);

    /* --------------------------------------------------------------------------------------------
     * See whether this instance references a valid database and node structure.
    */
    SQMOD_NODISCARD bool IsValid() const
    {
        return m_Handle;
    }

    /* --------------------------------------------------------------------------------------------
     * Release the manages handles/pointers and become a null instance.
    */
    void Release();

    /* --------------------------------------------------------------------------------------------
     * Retrieve the database associated with the managed handle/pointer.
    */
    SQMOD_NODISCARD Database GetDatabase() const;

    /* --------------------------------------------------------------------------------------------
     * Return the number of active references to the managed database instance.
    */
    SQMOD_NODISCARD uint32_t GetRefCount() const
    {
        return m_Handle.Count();
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the left record value.
    */
    Object GetLeftRecord()
    {
        return Object(SqTypeIdentity< ULongInt >{}, SqVM(), ConvTo< uint64_t >::From(SQMOD_GET_VALID(*this).left_record));
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the right record value.
    */
    Object GetRightRecord()
    {
      return Object(SqTypeIdentity< ULongInt >{}, SqVM(), ConvTo< uint64_t >::From(SQMOD_GET_VALID(*this).right_record));
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the left record value type.
    */
    SQInteger GetLeftRecordType()
    {
        return static_cast< SQInteger >(SQMOD_GET_VALID(*this).left_record_type);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the right record value type.
    */
    SQInteger GetRightRecordType()
    {
        return static_cast< SQInteger >(SQMOD_GET_VALID(*this).right_record_type);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the left record entry data list.
    */
    Object GetLeftRecordEntryDataList();

    /* --------------------------------------------------------------------------------------------
     * Retrieve the right record entry data list.
    */
    Object GetRightRecordEntryDataList();

    /* --------------------------------------------------------------------------------------------
     * Retrieve the left record entry data.
    */
    static SQInteger GetLeftRecordEntryData(HSQUIRRELVM vm)
    {
        return GetRecordEntryData(vm, false);
    }

    /* --------------------------------------------------------------------------------------------
     * Retrieve the left record entry data.
    */
    static SQInteger GetRightRecordEntryData(HSQUIRRELVM vm)
    {
        return GetRecordEntryData(vm, true);
    }

protected:

    /* --------------------------------------------------------------------------------------------
     * Shared function to retrieve the left/right record entry data.
    */
    static SQInteger GetRecordEntryData(HSQUIRRELVM vm, bool right);
};

} // Namespace:: SqMod