////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
// All rights reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// THIS IS AUTO-GENERATED CODE.  PLEASE DO NOT EDIT (File bug reports against tools).
///
/// Auto-generated by: Parameter Parser V7.4.1 (8cca6579792b9fcef3bc725ff070c5ec453c7c85)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  parameterutils.h
/// @brief Auto-generated Chromatix parameter file
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef PARAMETERUTILS_H
#define PARAMETERUTILS_H

#include "parametertypes.h"

#include <typeinfo>
#include <string>
#include <thread>
#include <ctime>
#include <atomic>
#include <type_traits>
#include <unordered_map>

#ifdef PARAMETER_USE_MUTEX
#ifdef PARAMETER_USE_UNIQUE
#else
#ifdef __ZEPHYR__
#error "Shared mutex is not compatible with Zephyr OS, use the --unique Parameter Parser command line option"
#endif
#include <shared_mutex>
#endif
#endif

#define PARAMETER_MIN(lhs, rhs)     ( (lhs) < (rhs) ? (lhs) : (rhs) )
#define PARAMETER_MAX(lhs, rhs)     ( (lhs) > (rhs) ? (lhs) : (rhs) )
#define PARAMETER_ABS(value)        ( (value) < 0 ? -(value) : (value) )
#define REMAINDER(bytes, alignment) ( (bytes % alignment) > 0 ? (alignment - (bytes % alignment)) : 0 )
#define MAX_FILE_LENGTH 1024
#define READ_BUF_COUNT  3
#define READ_BUF_LENGTH 1024

#ifndef __ZEPHYR__
#define IS_ALIGNED(value)           ( (UINT64)(value) % 8 == 0 )
#endif

#ifdef PARAMETER_USE_MUTEX
#ifdef __ZEPHYR__
#include <zephyr/kernel.h>
#else
#include <mutex>
#endif

class ParameterMutex
{
public:
    ParameterMutex()
    {
#ifdef __ZEPHYR__
        k_mutex_init(&m_mutex);
#endif
    }

    void lock()
    {
#ifdef __ZEPHYR__
        k_mutex_lock(&m_mutex, K_FOREVER);
#else
        m_mutex.lock();
#endif
    }

    void unlock()
    {
#ifdef __ZEPHYR__
        k_mutex_unlock(&m_mutex);
#else
        m_mutex.unlock();
#endif
    }

private:
#ifdef __ZEPHYR__
    k_mutex m_mutex;
#else
    std::recursive_mutex m_mutex;
#endif
};

class ParameterMutexLocker
{
public:
    ParameterMutexLocker(ParameterMutex& mutex)
        : m_mutex(mutex)
    {
        m_mutex.lock();
    }
    ~ParameterMutexLocker()
    {
        m_mutex.unlock();
    }

    ParameterMutex& m_mutex;
};
#endif

class ParameterParserDataType
{
public:
    static constexpr const CHAR* const Module    = "Module";
    static constexpr const CHAR* const Structure = "Structure";
    static constexpr const CHAR* const Enum      = "Enum";
    static constexpr const CHAR* const Boolean   = "Boolean";
    static constexpr const CHAR* const Int8      = "Int8";
    static constexpr const CHAR* const UInt8     = "UInt8";
    static constexpr const CHAR* const Int16     = "Int16";
    static constexpr const CHAR* const UInt16    = "UInt16";
    static constexpr const CHAR* const Int32     = "Int32";
    static constexpr const CHAR* const UInt32    = "UInt32";
    static constexpr const CHAR* const Int64     = "Int64";
    static constexpr const CHAR* const UInt64    = "UInt64";
    static constexpr const CHAR* const Float     = "Float";
    static constexpr const CHAR* const Double    = "Double";
    static constexpr const CHAR* const String    = "String";
};

class IParameterLoggingAPI;
class ParameterLogging
{
public:

    enum class ParameterLogLevel
    {
        Debug,
        Warning,
        Error
    };
    static constexpr INT32 MESSAGE_LEN = 4096;
    static void Write(IParameterLoggingAPI* const logAPI, ParameterLogLevel level, const CHAR* const str, ...);
    static void WriteFL(IParameterLoggingAPI* const logAPI, ParameterLogLevel level, const CHAR* const file, INT32 const line, const CHAR* const str, ...);
};

class IParameterLoggingAPI
{
public:
    virtual const CHAR* GetLoggingIdentifier() = 0;
    virtual bool LoggingEnabled(ParameterLogging::ParameterLogLevel level) = 0;

    virtual ~IParameterLoggingAPI() {}
};

#define PARAMETER_LOG_ERROR(logAPI, ...)      ParameterLogging::Write(logAPI, ParameterLogging::ParameterLogLevel::Error,   ##__VA_ARGS__)
#define PARAMETER_LOG_WARNING(logAPI, ...)    ParameterLogging::Write(logAPI, ParameterLogging::ParameterLogLevel::Warning, ##__VA_ARGS__)
#define PARAMETER_LOG_DEBUG(logAPI, ...)      ParameterLogging::Write(logAPI, ParameterLogging::ParameterLogLevel::Debug,   ##__VA_ARGS__)

struct ParameterRefCount
{
    PARAMETER_INLINE ParameterRefCount()
    {
        m_refCount = 0U;
    }
    PARAMETER_INLINE ParameterRefCount(INT32 initial)
    {
        m_refCount = initial;
    }
    PARAMETER_INLINE INT32 Get() const
    {
        return m_refCount;
    }
    PARAMETER_INLINE void Set(INT32 value)
    {
        m_refCount = value;
    }
    PARAMETER_INLINE INT32 Add(INT32 value)
    {
        if (value >= 0)
        {
            return m_refCount += value;
        }
        else
        {
            return m_refCount -= (-value);
        }
    }
    PARAMETER_INLINE INT32 AddRef()
    {
        return m_refCount++;
    }
    PARAMETER_INLINE INT32 Release()
    {
        return m_refCount--;
    }
    PARAMETER_INLINE void operator=(const ParameterRefCount& rhs)
    {
        m_refCount = rhs.m_refCount.load();
    }
    PARAMETER_INLINE void operator=(INT32 value)
    {
        m_refCount = value;
    }
    PARAMETER_INLINE operator INT32() const
    {
        return m_refCount.load();
    }
    PARAMETER_INLINE INT32 operator++(int)
    {
        return m_refCount++;
    }
    PARAMETER_INLINE INT32 operator--(int)
    {
        return m_refCount--;
    }
    PARAMETER_INLINE INT32 operator+=(UINT32 value)
    {
        return m_refCount += (INT32)value;
    }
    PARAMETER_INLINE INT32 operator+=(INT32 value)
    {
        return Add(value);
    }
    PARAMETER_INLINE INT32 operator-=(UINT32 value)
    {
        return m_refCount -= (INT32)value;
    }
    PARAMETER_INLINE INT32 operator-=(INT32 value)
    {
        return Add(-value);
    }
private:
    std::atomic<INT32> m_refCount;
};

class ParameterBinaryFile
{
public:
    static constexpr BYTE BINARY_FLAG_FLOAT     = 0x01;
    static constexpr BYTE BINARY_FLAG_POINTER   = 0x02;
    static constexpr BYTE BINARY_FLAG_LIST      = 0x04;
    static constexpr BYTE BINARY_FLAG_ATTRIBUTE = 0x08;

    // Borrowing an unused binary flags to save memory
    static constexpr BYTE FLAG_FIXED = 0x80; // Is a fixed array

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ParameterBinaryFile Constructor
    ///
    /// Constructing the ParameterBinaryFile object will open the file and add a reference if the file is valid
    /// After constructing, check the return value of IsValid() to verify if the file was opened
    ///
    /// @param fileName  Name of the file to open
    /// @param logAPI    Logging API used for logging error messages
    /// @param CRCCheck  Check CRC if true
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ParameterBinaryFile(
        const CHAR*           fileName,
        IParameterLoggingAPI* logAPI);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ParameterBinaryFile Descructor
    ///
    /// Deconstruct the ParameterBinaryFile object will close the file if opened
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ~ParameterBinaryFile();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FileName
    ///
    /// Returns the file name
    ///
    /// @return File Name
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    PARAMETER_INLINE const CHAR* FileName()
    {
        return m_fileName;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Length
    ///
    /// Returns the file length
    ///
    /// @return File Length
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    PARAMETER_INLINE UINT32 Length()
    {
        return m_length;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Read
    ///
    /// Reads the specified number of bytes from the file at the specified offset + pos
    ///
    /// @param value     Buffer to read into
    /// @param offset    Location in the file to start from
    /// @param pos       offset + position in the file to read from, position is updated after read
    /// @param count     Number of bytes to read
    /// @param alignment Number of bytes to align the returned pos value by
    ///
    /// @return Buffer Pointer or null if read failed
    ///                Caller is responsible for freeing the returned buffer using PARAMETER_DELETE[]
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    bool Read(
        BYTE* const   value,
        UINT32 const  offset,
        UINT32&       pos,
        SIZE_T const  count,
        BYTE const    alignment);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Read
    ///
    /// Reads the specified number of bytes from the file at the specified offset
    ///
    /// @param offset  Location in the file to start reading
    /// @param count   Number of bytes to read
    ///
    /// @return Buffer Pointer or null if read failed
    ///                Caller is responsible for freeing the returned buffer using PARAMETER_DELETE[]
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BYTE* Read(
        UINT32 const offset,
        SIZE_T const count);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsValid
    ///
    /// Check if the file exists and can be opened
    ///
    /// @return true if the file was successfully opened at construction time
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    PARAMETER_INLINE bool IsValid()
    {
        return m_isValid;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Reference
    ///
    /// Add or remove file references.  Opens or closes the file as needed
    ///
    /// @param adjust  Number of references to add (or remove if negative)
    ///
    /// @return The current reference count after the change is applied
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    INT32 Reference(
        INT32 adjust);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ValidateCRC
    ///
    /// @brief Reads and validates CRC value in the binary buffer
    ///
    /// @param buffer   Binary parameter buffer
    /// @param length   Length of the binary parameter buffer
    /// @param crc64    Use 64-bit CRC
    /// @param logAPI  Set logAPI for error reporting
    ///
    /// @return True if CRC is valid
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static bool ValidateCRC(
        BYTE* const           buffer,
        const UINT32          length,
        bool const            crc64,
        IParameterLoggingAPI* logAPI);

private:
    void Close();
    void Open(bool logFailures);

    struct ReadBuffer
    {
        BYTE   Buffer[READ_BUF_LENGTH];
        UINT32 Offset;
        UINT32 Length;

        PARAMETER_INLINE bool IsValid(
            UINT32 filePos,
            SIZE_T count)
        {
            return filePos + count > 0 && filePos >= Offset && filePos + count <= Offset + Length;
        }
    };
    struct ReadBuffer* GetBuffer(
        UINT32 filePos,
        SIZE_T count);

    FILE*             m_file;
    UINT32            m_length;
    ParameterRefCount m_refCnt;
    ReadBuffer        m_readBufs[READ_BUF_COUNT];
    bool              m_useReadBufs;
    CHAR              m_fileName[MAX_FILE_LENGTH];
    bool              m_isValid;    // File exists and can be opened
    bool              m_isModified;
    time_t            m_modTime;
#ifdef PARAMETER_USE_MUTEX
    ParameterMutex    m_pbfMutex;
#endif
    IParameterLoggingAPI* m_logAPI;
};

template<typename T> class PList
{
public:
    PList()
    {
        m_count  = 0;
        m_bufCnt = 0;
        m_list   = nullptr;
    }

    PList(const T& rhs)
    {
        m_count  = 0;
        m_bufCnt = 0;
        m_list   = nullptr;
        Add(rhs);
    }

    PList(const PList<T>& rhs)
    {
        *this = rhs;
    }

    ~PList()
    {
        Clear();
    }

    PList& operator=(const PList& rhs)
    {
        if (&rhs != this)
        {
            Clear();
            for (UINT32 i = 0; i < rhs.Count(); i++)
            {
                Add(rhs.m_list[i]);
            }
        }

        return *this;
    }

    PARAMETER_INLINE void Add(T value)
    {
        Insert(Count(), value);
    }

    void Insert(UINT32 index, T value)
    {
        bool valid = m_list != nullptr;
        if (m_count >= m_bufCnt)
        {
            SIZE_T endloc = m_bufCnt;
            m_bufCnt++;
            T* newPtr = (T*)PARAMETER_REALLOC(m_list, m_bufCnt * sizeof(T));
            valid = newPtr != nullptr;
            if (valid)
            {
                // Initialize the appended memory block
                PARAMETER_MEMSET(&newPtr[endloc], 0, sizeof(T));
                m_list = newPtr;
            }
        }

        if (valid)
        {
            for (UINT32 i = m_count; i > index; i--)
            {
                m_list[i] = m_list[i - 1];
            }
            m_list[index] = value;
            m_count++;
        }
    }

    void Remove(T value)
    {
        INT32 index = IndexOf(value);
        if (index >= 0)
        {
            RemoveAt(index);
        }
    }

    void RemoveAt(UINT32 index, UINT32 count = 1)
    {
        for (SIZE_T i = index; i + count < m_count; i++)
        {
            m_list[i] = m_list[i + count];
        }
        m_count -= count;
    }

    INT32 IndexOf(T value)
    {
        INT32 result = -1;

        for (UINT32 i = 0; result < 0 && i < m_count; i++)
        {
            if (m_list[i] == value)
            {
                result = i;
            }
        }
        return result;
    }

    PARAMETER_INLINE bool Contains(T value)
    {
        return IndexOf(value) >= 0;
    }

    void Clear()
    {
        PARAMETER_FREE(m_list);
        m_count  = 0;
        m_bufCnt = 0;
        m_list   = nullptr;
    }

    T& operator[] (UINT32 index) const
    {
        static T dummy = T{};
        if (index >= m_count)
        {
            return dummy;
        }

        return m_list[index];
    }

    PARAMETER_INLINE UINT32 Count() const
    {
        return m_count;
    }

    PARAMETER_INLINE T* ToArray() const
    {
        return m_list;
    }

private:
    T*     m_list;
    UINT32 m_count;
    UINT32 m_bufCnt;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Parameter Definition
///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
enum ParameterDefinitionType
{
    // Config Entries
    ParameterDefinitionType_ScenarioMode    = 0,
    ParameterDefinitionType_ScenarioSubMode = 1,
    ParameterDefinitionType_Pipeline        = 2,

    // Structure Entries
    ParameterDefinitionType_Module         = 4,
    ParameterDefinitionType_Structure      = 5,
    ParameterDefinitionType_EnumDefinition = 6,

    // Data Entries
    ParameterDefinitionType_Signed8Bits    = 8,
    ParameterDefinitionType_Unsigned8Bits  = 9,
    ParameterDefinitionType_Signed16Bits   = 10,
    ParameterDefinitionType_Unsigned16Bits = 11,
    ParameterDefinitionType_Signed32Bits   = 12,
    ParameterDefinitionType_Unsigned32Bits = 13,
    ParameterDefinitionType_Signed64Bits   = 14,
    ParameterDefinitionType_Unsigned64Bits = 15,
    ParameterDefinitionType_Float          = 16,
    ParameterDefinitionType_Double         = 17,
    ParameterDefinitionType_Hex8Bits       = 18,
    ParameterDefinitionType_Hex16Bits      = 19,
    ParameterDefinitionType_Hex32Bits      = 20,
    ParameterDefinitionType_Hex64Bits      = 21,
    ParameterDefinitionType_Boolean        = 22,
    ParameterDefinitionType_Enum           = 23,
    ParameterDefinitionType_String         = 24,
    ParameterDefinitionType_AlphaNumeric   = 25,
    ParameterDefinitionType_IDString       = 26,
    ParameterDefinitionType_IDStringRef    = 27,
    ParameterDefinitionType_Attribute      = 28
};

struct ParameterDefinitionModule
{
    ParameterDefinitionModule();
    ParameterDefinitionModule(
        BYTE* const                 buffer,
        UINT32 const                length,
        UINT32&                     pos,
        BYTE const                  alignment,
        IParameterLoggingAPI* const logAPI);
    ~ParameterDefinitionModule();

    UINT32 StructureID;
    UINT64 NameHash;
    CHAR*  Name;
};

struct ParameterDefinitionStructure;
struct ParameterDefinitionElementInfo
{
    ParameterDefinitionElementInfo(
        ParameterDefinitionStructure* structure = nullptr);
    ParameterDefinitionElementInfo(
        ParameterDefinitionType type,
        UINT32                  id,
        UINT16                  flags,
        UINT32                  minCount,
        UINT32                  maxCount);
    ~ParameterDefinitionElementInfo();

    PARAMETER_INLINE bool IsString() { return Type >= ParameterDefinitionType_String; }

    PARAMETER_INLINE bool IsFloat()   { return (Flags & ParameterBinaryFile::BINARY_FLAG_FLOAT) > 0; }
    PARAMETER_INLINE bool IsPointer() { return (Flags & ParameterBinaryFile::BINARY_FLAG_POINTER) > 0; }
    PARAMETER_INLINE bool IsFixed()   { return (Flags & ParameterBinaryFile::FLAG_FIXED) > 0; }
    PARAMETER_INLINE void SetFixed()  { Flags |= ParameterBinaryFile::FLAG_FIXED; }

    ParameterDefinitionType       Type;
    UINT32                        ID;
    UINT16                        Flags;
    UINT32                        MaxCount;
    UINT32                        ParentOffset; // Offset from the parent structure in the binary file
    ParameterDefinitionStructure* Structure;
};

struct ParameterDefinitionElement
{
    ParameterDefinitionElement(
        ParameterDefinitionStructure* structure = nullptr);
    ParameterDefinitionElement(
        BYTE* const                 buffer,
        UINT32 const                length,
        UINT32&                     pos,
        BYTE const                  alignment,
        IParameterLoggingAPI* const logAPI);
    ~ParameterDefinitionElement();

    PARAMETER_INLINE bool IsString()  { return Info != nullptr && Info->IsString(); }

    PARAMETER_INLINE bool IsFloat()   { return Info != nullptr && Info->IsFloat(); }
    PARAMETER_INLINE bool IsPointer() { return Info != nullptr && Info->IsPointer(); }
    PARAMETER_INLINE bool IsFixed()   { return Info != nullptr && Info->IsFixed(); }
    PARAMETER_INLINE void SetFixed()  { if (Info != nullptr) Info->SetFixed(); }

    bool IsStructVerified(PList<UINT32>& structuresChecked);
    size_t GetSize();

    UINT64                          NameHash;
    bool                            Verified;
    ParameterDefinitionElementInfo* Info;
    bool                            m_nameAllocated;
};

struct ParameterDefinitionStructure
{
    ParameterDefinitionStructure();
    ParameterDefinitionStructure(
        BYTE* const                 buffer,
        UINT32 const                length,
        UINT32&                     pos,
        BYTE const                  alignment,
        IParameterLoggingAPI* const logAPI);
    ~ParameterDefinitionStructure();

    ParameterDefinitionElement* FindChild(
        UINT64 const nameHash);

    void FreeChild(
        UINT64 const                nameHash,
        ParameterDefinitionElement* child);

    void PopulateOffsetSizeStructure(
        std::unordered_map<UINT32, ParameterDefinitionStructure*>* structures,
        IParameterLoggingAPI* const                                logAPI);

    bool IsVerified(PList<UINT32>& structuresChecked);

    UINT32                                                   StructureID;
    CHAR*                                                    TypeName;
    UINT64                                                   StructureHash;
    UINT32                                                   Size;
    std::unordered_map<UINT64, ParameterDefinitionElement*>* Children;
    PList<ParameterDefinitionElement*>*                      ChildOrder;
};

struct ParameterDefinitionEnumValue
{
    ParameterDefinitionEnumValue();
    ParameterDefinitionEnumValue(
        BYTE* const                 buffer,
        UINT32 const                length,
        UINT32&                     pos,
        BYTE const                  alignment,
        IParameterLoggingAPI* const logAPI);

    UINT32 Value;
    bool   IsValueEnum;
    CHAR*  Name;
    CHAR*  ValueString;
};

struct ParameterDefinitionEnum
{
    ParameterDefinitionEnum();
    ParameterDefinitionEnum(
        BYTE* const                 buffer,
        UINT32 const                length,
        UINT32&                     pos,
        BYTE const                  alignment,
        IParameterLoggingAPI* const logAPI);

    UINT32                               EnumID;
    CHAR*                                TypeName;
    UINT64                               EnumHash;
    PList<ParameterDefinitionEnumValue*> Values;
};

// Reads buffer value in little-endian format
class ParameterUtils
{
public:
    static constexpr INT32  UNLIMITED    = -1;
    static constexpr UINT32 MAX_DECIMALS = 10U;

    template<typename T> static bool IsTypeMatch(ParameterDefinitionElement* element)
    {
        bool result = true;
        if (element != nullptr && element->Info != nullptr)
        {
            if (element->IsFloat())
            {
                result = std::is_same<T, float>::value;
            }
            else
            {
                switch (element->Info->Type)
                {
                case ParameterDefinitionType_Signed8Bits:
                {
                    result = std::is_same<T, INT8>::value;
                    break;
                }
                case ParameterDefinitionType_Unsigned8Bits:
                case ParameterDefinitionType_Hex8Bits:
                {
                    result = std::is_same<T, UINT8>::value;
                    break;
                }
                case ParameterDefinitionType_Signed16Bits:
                {
                    result = std::is_same<T, INT16>::value;
                    break;
                }
                case ParameterDefinitionType_Unsigned16Bits:
                case ParameterDefinitionType_Hex16Bits:
                {
                    result = std::is_same<T, UINT16>::value;
                    break;
                }
                case ParameterDefinitionType_Signed32Bits:
                case ParameterDefinitionType_Boolean:
                {
                    result = std::is_same<T, INT32>::value;
                    break;
                }
                case ParameterDefinitionType_Unsigned32Bits:
                case ParameterDefinitionType_Hex32Bits:
                case ParameterDefinitionType_Enum:
                {
                    result = std::is_same<T, UINT32>::value;
                    break;
                }
                case ParameterDefinitionType_Signed64Bits:
                {
                    result = std::is_same<T, INT64>::value;
                    break;
                }
                case ParameterDefinitionType_Unsigned64Bits:
                case ParameterDefinitionType_Hex64Bits:
                {
                    result = std::is_same<T, UINT64>::value;
                    break;
                }
                case ParameterDefinitionType_Float:
                {
                    result = std::is_same<T, float>::value;
                    break;
                }
                case ParameterDefinitionType_Double:
                {
                    result = std::is_same<T, double>::value;
                    break;
                }
                default:
                    result = false;
                    break;
                }
            }
        }

        return result;
    }

    template<typename T> static bool Read(
        T*                          value,
        ParameterDefinitionElement* element,
        const BYTE* const           buffer,
        UINT32 const                length,
        UINT32&                     pos,
        BYTE const                  alignment,
        IParameterLoggingAPI* const logAPI)
    {
        bool result = false;
        if (value != nullptr)
        {
            if (element == nullptr || element->Info == nullptr || IsTypeMatch<T>(element))
            {
                result = Read(value, buffer, length, pos, alignment, logAPI);
            }
            else
            {
                result = true;
                switch (element->Info->Type)
                {
                case ParameterDefinitionType_Signed8Bits:
                {
                    INT8 val = 0;
                    Read(&val, buffer, length, pos, alignment, logAPI);
                    *value = (T)val;
                    break;
                }
                case ParameterDefinitionType_Unsigned8Bits:
                case ParameterDefinitionType_Hex8Bits:
                {
                    UINT8 val = 0;
                    Read(&val, buffer, length, pos, alignment, logAPI);
                    *value = (T)val;
                    break;
                }
                case ParameterDefinitionType_Signed16Bits:
                {
                    INT16 val = 0;
                    Read(&val, buffer, length, pos, alignment, logAPI);
                    *value = (T)val;
                    break;
                }
                case ParameterDefinitionType_Unsigned16Bits:
                case ParameterDefinitionType_Hex16Bits:
                {
                    UINT16 val = 0;
                    Read(&val, buffer, length, pos, alignment, logAPI);
                    *value = (T)val;
                    break;
                }
                case ParameterDefinitionType_Signed32Bits:
                {
                    INT32 val = 0;
                    Read(&val, buffer, length, pos, alignment, logAPI);
                    *value = (T)val;
                    break;
                }
                case ParameterDefinitionType_Unsigned32Bits:
                case ParameterDefinitionType_Hex32Bits:
                case ParameterDefinitionType_Boolean:
                case ParameterDefinitionType_Enum:
                {
                    UINT32 val = 0;
                    Read(&val, buffer, length, pos, alignment, logAPI);
                    *value = (T)val;
                    break;
                }
                case ParameterDefinitionType_Signed64Bits:
                {
                    INT64 val = 0;
                    Read(&val, buffer, length, pos, alignment, logAPI);
                    *value = (T)val;
                    break;
                }
                case ParameterDefinitionType_Unsigned64Bits:
                case ParameterDefinitionType_Hex64Bits:
                {
                    UINT64 val = 0;
                    Read(&val, buffer, length, pos, alignment, logAPI);
                    *value = (T)val;
                    break;
                }
                case ParameterDefinitionType_Float:
                {
                    float val = 0;
                    Read(&val, buffer, length, pos, alignment, logAPI);
                    *value = (T)val;
                    break;
                }
                case ParameterDefinitionType_Double:
                {
                    double val = 0;
                    Read(&val, buffer, length, pos, alignment, logAPI);
                    *value = (T)val;
                    break;
                }
                default:
                    result = false;
                    PARAMETER_LOG_ERROR(logAPI, "%s: Invalid read type %u\n", __FUNCTION__, (UINT32)element->Info->Type);
                    break;
                }
            }
        }

        return result;
    }

    template<typename T> static bool Read(
        T*                          value,
        const BYTE* const           buffer,
        UINT32 const                length,
        UINT32&                     pos,
        BYTE const                  alignment,
        IParameterLoggingAPI* const logAPI)
    {
        constexpr SIZE_T OBJ_SIZE = sizeof(T);
        if (pos + OBJ_SIZE <= length)
        {
            PARAMETER_MEMCPY(value, OBJ_SIZE, &buffer[pos], OBJ_SIZE);
            pos += PARAMETER_MAX(OBJ_SIZE, alignment);
            return true;
        }
        else
        {
            PARAMETER_LOG_ERROR(logAPI, "Failed to read %lld bytes from binary file offset %d, length %d\n", OBJ_SIZE, pos, length);
        }
        return false;
    }

    template<typename T> static bool Write(
        T const               value,
        BYTE*                 buffer,
        UINT32 const          length,
        UINT32&               pos,
        BYTE const            alignment,
        IParameterLoggingAPI* logAPI)
    {
        constexpr SIZE_T OBJ_SIZE = sizeof(T);
        if (pos + OBJ_SIZE <= length)
        {
            PARAMETER_MEMCPY(&buffer[pos], OBJ_SIZE, &value, OBJ_SIZE);
            pos += PARAMETER_MAX(OBJ_SIZE, alignment);
            return true;
        }
        else
        {
            PARAMETER_LOG_ERROR(logAPI, "Failed to write %lld bytes to binary offset %d, length %d\n", OBJ_SIZE, pos, length);
        }
        return false;
    }

    template<typename T, typename F> static bool ReadArray(
        T*                          array,
        const BYTE* const           buffer,
        UINT32 const                length,
        UINT32&                     pos,
        UINT32 const                count,
        BYTE const                  alignment,
        IParameterLoggingAPI*       logAPI)
    {
        bool result = false;
        if (array != nullptr)
        {
            F* from = PARAMETER_NEW F[count];
            if (from != nullptr)
            {
                result = ReadArray(from, buffer, length, pos, count, alignment, logAPI);

                if (result)
                {
                    for (UINT32 i = 0; i < count; i++)
                    {
                        array[i] = (T)from[i];
                    }
                }
                PARAMETER_DELETE[] from;
            }
        }

        return result;
    }

    template<typename T> static bool ReadArray(
        T*                          value,
        ParameterDefinitionElement* element,
        const BYTE* const           buffer,
        UINT32 const                length,
        UINT32&                     pos,
        UINT32 const                count,
        BYTE const                  alignment,
        IParameterLoggingAPI*       logAPI)
    {
        bool result = false;
        if (element == nullptr || element->Info == nullptr || IsTypeMatch<T>(element))
        {
            result = ReadBuffer((BYTE*)value, buffer, length, pos, count * sizeof(T), alignment, logAPI);
        }
        else
        {
            if (element->IsFloat() || element->Info->Type == ParameterDefinitionType_Float)
            {
                result = ReadArray<T, float>(value, buffer, length, pos, count, alignment, logAPI);
            }
            else if (element->Info->Type == ParameterDefinitionType_Double)
            {
                result = ReadArray<T, double>(value, buffer, length, pos, count, alignment, logAPI);
            }
            else
            {
                ReadArrayNoFloat(value, element, buffer, length, pos, count, alignment, logAPI);
            }
        }

        return result;
    }

    template<typename T> static bool ReadArrayNoFloat(
        T*                          value,
        ParameterDefinitionElement* element,
        const BYTE* const           buffer,
        UINT32 const                length,
        UINT32&                     pos,
        UINT32 const                count,
        BYTE const                  alignment,
        IParameterLoggingAPI*       logAPI)
    {
        bool result = false;
        if (element == nullptr || element->Info == nullptr || IsTypeMatch<T>(element))
        {
            result = ReadBuffer((BYTE*)value, buffer, length, pos, count * sizeof(T), alignment, logAPI);
        }
        else
        {
            if (element->IsFloat())
            {
                result = ReadArray<T, UINT32>(value, buffer, length, pos, count, alignment, logAPI);
            }
            else
            {
                switch (element->Info->Type)
                {
                case ParameterDefinitionType_Signed8Bits:
                {
                    result = ReadArray<T, INT8>(value, buffer, length, pos, count, alignment, logAPI);
                    break;
                }
                case ParameterDefinitionType_Unsigned8Bits:
                case ParameterDefinitionType_Hex8Bits:
                {
                    result = ReadArray<T, UINT8>(value, buffer, length, pos, count, alignment, logAPI);
                    break;
                }
                case ParameterDefinitionType_Signed16Bits:
                {
                    result = ReadArray<T, INT16>(value, buffer, length, pos, count, alignment, logAPI);
                    break;
                }
                case ParameterDefinitionType_Unsigned16Bits:
                case ParameterDefinitionType_Hex16Bits:
                {
                    result = ReadArray<T, UINT16>(value, buffer, length, pos, count, alignment, logAPI);
                    break;
                }
                case ParameterDefinitionType_Signed32Bits:
                case ParameterDefinitionType_Boolean:
                {
                    result = ReadArray<T, INT32>(value, buffer, length, pos, count, alignment, logAPI);
                    break;
                }
                case ParameterDefinitionType_Unsigned32Bits:
                case ParameterDefinitionType_Hex32Bits:
                case ParameterDefinitionType_Enum:
                {
                    result = ReadArray<T, UINT32>(value, buffer, length, pos, count, alignment, logAPI);
                    break;
                }
                case ParameterDefinitionType_Signed64Bits:
                {
                    result = ReadArray<T, INT64>(value, buffer, length, pos, count, alignment, logAPI);
                    break;
                }
                case ParameterDefinitionType_Unsigned64Bits:
                case ParameterDefinitionType_Hex64Bits:
                {
                    result = ReadArray<T, UINT64>(value, buffer, length, pos, count, alignment, logAPI);
                    break;
                }
                case ParameterDefinitionType_Float:
                {
                    // It is possible to get here only by calling ParameterFileSymbolTableEntry::ReadEnumArray
                    // so we can assume the type is an enum
                    PARAMETER_LOG_WARNING(logAPI, "%s: Attempt to convert a float value to an enum\n", __FUNCTION__);
                    result = ReadArray<T, UINT32>(value, buffer, length, pos, count, alignment, logAPI);
                    break;
                }
                case ParameterDefinitionType_Double:
                {
                    // It is possible to get here only by calling ParameterFileSymbolTableEntry::ReadEnumArray
                    // so we can assume the type is an enum
                    PARAMETER_LOG_WARNING(logAPI, "%s: Attempt to convert a double value to an enum\n", __FUNCTION__);
                    result = ReadArray<T, UINT64>(value, buffer, length, pos, count, alignment, logAPI);
                    break;
                }
                default:
                    PARAMETER_LOG_ERROR(logAPI, "%s: Invalid read type %u. XSD structure modified\n", __FUNCTION__, (UINT32)element->Info->Type);
                    break;
                }
            }
        }

        return result;
    }

    template<typename T> static bool ReadArray(
        T*                    value,
        const BYTE* const     buffer,
        UINT32 const          length,
        UINT32&               pos,
        UINT32 const          count,
        BYTE const            alignment,
        IParameterLoggingAPI* logAPI)
    {
        return ReadBuffer((BYTE*)value, buffer, length, pos, count * sizeof(T), alignment, logAPI);
    }

    template<typename T> static T* ReadArray(
        ParameterDefinitionElement* element,
        const BYTE* const           buffer,
        UINT32 const                length,
        UINT32&                     pos,
        UINT32 const                count,
        BYTE const                  alignment,
        IParameterLoggingAPI*       logAPI)
    {
        T* result = PARAMETER_NEW T[count];
        if (!ReadArray(result, element, buffer, length, pos, count, alignment, logAPI))
        {
            PARAMETER_DELETE[] result;
            result = nullptr;
        }
        return result;
    }

    template<typename T> static T* ReadArrayNoFloat(
        ParameterDefinitionElement* element,
        const BYTE* const           buffer,
        UINT32 const                length,
        UINT32&                     pos,
        UINT32 const                count,
        BYTE const                  alignment,
        IParameterLoggingAPI*       logAPI)
    {
        T* result = PARAMETER_NEW T[count];
        if (!ReadArrayNoFloat(result, element, buffer, length, pos, count, alignment, logAPI))
        {
            PARAMETER_DELETE[] result;
            result = nullptr;
        }
        return result;
    }

    template<typename T> static T* ReadArray(
        const BYTE* const     buffer,
        UINT32 const          length,
        UINT32&               pos,
        UINT32 const          count,
        BYTE const            alignment,
        IParameterLoggingAPI* logAPI)
    {
        T* result = PARAMETER_NEW T[count];
        if (!ReadBuffer((BYTE*)result, buffer, length, pos, count * sizeof(T), alignment, logAPI))
        {
            PARAMETER_DELETE[] result;
            result = nullptr;
        }
        return result;
    }

    static bool ReadString(
        CHAR* const   value,
        BYTE* const   buffer,
        UINT32 const  length,
        UINT32&       pos,
        UINT32 const  destStrSize,
        UINT32 const  maxChars,
        BYTE const    alignment,
        IParameterLoggingAPI* logAPI);

    static CHAR* ReadString(
        BYTE* const   buffer,
        UINT32 const  length,
        UINT32&       pos,
        UINT32 const  maxChars,
        BYTE const    alignment);

    static bool ReadBuffer(
        BYTE* const           value,
        const BYTE* const     buffer,
        UINT32 const          length,
        UINT32&               pos,
        UINT32 const          count,
        BYTE const            alignment,
        IParameterLoggingAPI* logAPI);

    static bool WriteString(
        const CHAR*   value,
        BYTE*         buffer,
        UINT32 const  length,
        UINT32&       pos,
        bool const    includeNul,
        IParameterLoggingAPI* logAPI);

    static INT32 GetStringPos(
        const CHAR* const input,
        CHAR const  ch);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetSubString - Get substring from input (returns up to the separator position)
    ///
    /// Return value - New input string position (separator or string terminator position)
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static UINT32 GetSubString(
        const CHAR* const input,
        CHAR const        separator,
        CHAR* const       subString,
        UINT32 const      size);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetVariable - Get variable name and array index  (if exists) from input string
    ///
    /// Return value - new input string position
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static UINT32 GetVariable(
        const CHAR* const input,
        CHAR* const name,
        UINT32&     index,
        SIZE_T const size);

    static double StringToDouble(
        const CHAR* const input,
        bool&             valid);

    static PARAMETER_INLINE double StringToDouble(
        const CHAR* const input)
    {
        bool valid = false;
        return StringToDouble(input, valid);
    }

    static void DoubleToString(
        double const input,
        CHAR* const  string,
        UINT32 const size,
        UINT32 const decimals,
        bool&  valid);

    static PARAMETER_INLINE void DoubleToString(
        double const input,
        CHAR*  const string,
        UINT32 const size,
        UINT32 const decimals = MAX_DECIMALS)
    {
        bool valid = false;
        DoubleToString(input, string, size, decimals, valid);
    }
};

struct ParameterParserInfo
{
    static constexpr INT32 MAX_VALUE = 1024;

    ParameterParserInfo();
    ParameterParserInfo(const CHAR* const name, const CHAR* const type);
    ParameterParserInfo(const CHAR* const name, const CHAR* const type, double const value, UINT32 const decimals = ParameterUtils::MAX_DECIMALS);
    ParameterParserInfo(const CHAR* const name, const CHAR* const type, const CHAR* const value);
    ParameterParserInfo(const CHAR* const name, const CHAR* const type, bool const isArray, bool const isOptional, UINT32 const elements);

    const CHAR* Name;
    const CHAR* Type;
    CHAR        Value[MAX_VALUE];
    UINT32      IsArray;    // True if is an array
    UINT32      IsOptional; // True if is an optional parameter
    UINT32      Elements;   // Number of array elements. If IsOptional, 1 means optional value exists
};

class DupObjInfo
{
public:
    DupObjInfo(INT32 const location);
    ~DupObjInfo();

    static bool Release(DupObjInfo* const obj);

    void*             Object;
    INT32             Location;
    ParameterRefCount RefCount;
};

#ifdef _WIN32
typedef std::thread::id ParameterThreadID;
#define gettid() std::this_thread::get_id()
#elif defined(__ZEPHYR__)
typedef UINT64 ParameterThreadID;
#define gettid() (UINT64)k_current_get()
#else
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30
#include <sys/syscall.h>
#define gettid() syscall(SYS_gettid)
#else
#include <unistd.h>
#endif
typedef INT64 ParameterThreadID;
#endif

class ParameterThreadIDClass
{
public:
    static PARAMETER_INLINE ParameterThreadID GetCurrent()
    {
        return gettid();
    }

    static ParameterThreadID NOT_OWNED;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// IParameterDataAPI
///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class IParameterDataAPI : public IParameterLoggingAPI
{
public:

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetModeTableCount
    ///
    /// @brief Returns the number of mode tables
    ///
    /// @return the number of mode tables, 0 if a binary is not loaded
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual UINT32 GetModeTableCount() = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetModeTableNames
    ///
    /// @brief Fills in names with a list of mode table names
    ///
    /// @param names   [out] List of mode table names
    ///
    /// @return True if at least one mode table exists
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual bool GetModeTableNames(
        PList<const CHAR*>& names) = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetValue
    ///
    /// @brief Gets the module value(s) specified by the mode path, and variable path
    ///
    /// @param modeTableIndex  Index of the Mode Table
    /// @param modePath        Pipe '|' separated Mode path
    ///                        Example: "0|1.0|2.0" (represents Default|Sensor.0|Preview)
    /// @param path            Dot '.' separated Path to the structure (or variable if valriable is nullptr) to set
    ///                        Example: cc14_ipr_v2.control_variables
    /// @param variable        Variable to get, if nullptr, path is used explicitly
    ///                        Example: control_var_type[2]
    /// @param value           Output Value string, comma separated list of array values
    /// @param size            Size of the Value string
    ///
    /// @return True value was found and set
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual bool GetValue(
        BYTE const        modeTableIndex,
        const CHAR* const modePath,
        const CHAR* const path,
        const CHAR* const variable,
        CHAR* const       value,
        UINT32 const      size) = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetValue
    ///
    /// @brief Sets the module value specified by the mode branch, and variable path
    ///
    /// @param modeTableIndex  Index of the Mode Table
    /// @param modePath        Pipe '|' separated Mode path
    ///                        Example: "0|1.0|2.0" (represents Default|Sensor.0|Preview)
    /// @param path            Dot '.' separated stucture Path to the variable location
    ///                        Example: cc14_ipr_v2.control_variables
    /// @param variable        Variable to set
    ///                        Example: control_var_type[2]
    /// @param value           Value to set, will be parsed from string to the variable's type
    ///
    /// @return True value was found and set
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual bool SetValue(
        BYTE const        modeTableIndex,
        const CHAR* const modePath,
        const CHAR* const path,
        const CHAR* const variable,
        const CHAR* const value) = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetInfo
    ///
    /// @brief Returns information about a specific parameter, or returns the list of parameters from the specified path
    ///
    /// @param modeTableIndex  Index of the Mode Table
    /// @param modePath        Pipe '|' separated Mode path. If nullptr, last accessed tuning mode branch will be used
    /// @param path            Dot '.' separated Path to the variable to set
    ///                        Example: cc14_ipr_v2.control_variables.control_var_type
    /// @param info            list of info
    ///
    /// @return True if the path was found
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual bool GetInfo(
        BYTE const                  modeTableIndex,
        const CHAR* const           modePath,
        const CHAR* const           path,
        PList<ParameterParserInfo>& info) = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetActiveModes
    ///
    /// @brief Returns the currently active tuning mode branches
    ///
    /// @param modeTableIndex  Index of the Mode Table
    /// @param path            Output Pipe '|' separated Mode path, multiple mode paths separated by a semi colon ';'
    /// @param pathSize        Size of path character array, recommended min size is MIN_PATH_SIZE, assuming 7 modes per branch
    ///                        times maximum number of active modes you would like
    ///
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual void GetActiveModes(
        BYTE const   modeTableIndex,
        CHAR* const  path,
        UINT32 const pathSize) = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetChildModes
    ///
    /// @brief Returns The Mode Information from the given path.
    ///
    /// @param modeTableIndex  Index of the Mode Table
    /// @param requestPath     Pipe '|' separated Mode path
    ///                        Example: "0|1.0|2.0" (represents Default|Sensor.0|Preview)
    /// @param responsePath    Comma ',' separated, and nul terminated child modes string
    ///                        Example: "1.0,1.1,1.2" (represents Preview,Snapshot,Video)
    /// @param responseSize    Size of the responsePath array
    ///
    /// @return Number of characters written including the nul terminator
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual UINT32 GetChildModes(
        BYTE const  modeTableIndex,
        const CHAR* requestPath,
        BYTE*       responsePath,
        UINT32      responseSize) = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetModeShorthand
    ///
    /// @brief Converts an EzTune mode path into a SetManager mode path
    ///
    /// @param input        Pipe '|' separated EzTune Mode path
    ///                     Example: "Default|Sensor.0|Usecase.Preview"
    /// @param output       Pipe '|' separated SetManager Mode path
    ///                     Example: "0|1.0|2.0" (represents Default|Sensor.0|Usecase.Preview)
    ///
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual void GetModeShorthand(
        const CHAR* input,
        CHAR*       output,
        UINT32      length) = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ~iEzTuneDataAccessAPI
    ///
    /// @brief Virtual destructor to satisfy compiler requirements
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual ~IParameterDataAPI() {};
};

PARAMETER_PACK_BEGIN
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// struct ParameterCTValue
///
/// @brief Contains a control/trigger value
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct ParameterCTValue
{
    PARAMETER_INLINE ParameterCTValue()
    {
        EnumVal = 0;
        Value   = 0;
    }

    PARAMETER_INLINE ParameterCTValue(UINT32 enumVal, double value)
    {
        EnumVal = enumVal;
        Value   = value;
    }

    void ToString(CHAR* const str, UINT32 const size);

    UINT32 EnumVal;
    double Value;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// class ParameterTriggerIDValues
///
/// @brief Contains identifier trigger values
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ParameterTriggerIDValues
{
public:
    PARAMETER_INLINE ParameterTriggerIDValues()
    {
        Values = nullptr;
        Count  = 0;
    }

    PARAMETER_INLINE ParameterTriggerIDValues(
        const CHAR* const id)
    {
        ID     = id;
        Values = nullptr;
        Count  = 0;
    }

    PARAMETER_INLINE ParameterTriggerIDValues(
        const CHAR* const             id,
        const ParameterCTValue* const values,
        UINT32 const                  count)
    {
        ID     = id;
        Values = nullptr;
        Count  = 0;

        SetValues(values, count);
    }

    PARAMETER_INLINE ParameterTriggerIDValues(const ParameterTriggerIDValues& rhs)
    {
        *this = rhs;
    }

    ParameterTriggerIDValues& operator=(const ParameterTriggerIDValues& rhs)
    {
        if (&rhs != this)
        {
            Clear();
            ID = rhs.ID;

            SetValues(rhs.Values, rhs.Count);
        }

        return *this;
    }

    PARAMETER_INLINE void Clear()
    {
        PARAMETER_DELETE[] Values;
        Values = nullptr;
        Count  = 0;
    }

    void SetValues(
        const ParameterCTValue* const values,
        UINT32 const count);

    PARAMETER_STD_STRING ID;
    ParameterCTValue*    Values;
    UINT32               Count;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// class ParameterTriggerValues
///
/// @brief Contains module trigger values
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ParameterTriggerValues
{
public:

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ParameterTriggerValues constructor
    ///
    /// @brief Constructs the ParameterTriggerValues class
    ///
    /// @param module Module name
    /// @param modePath  Scenario mode path
    /// @param pipeline  Pipeline
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    PARAMETER_INLINE ParameterTriggerValues(
        const CHAR* const modePath,
        const CHAR* const module,
        const CHAR* const pipeline)
    {
        ModePath = modePath;
        Module   = module;
        Pipeline = pipeline;
        Clear();
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ParameterTriggerValues constructor
    ///
    /// @brief Constructs the ParameterTriggerValues class
    ///
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    PARAMETER_INLINE ParameterTriggerValues()
    {
        Clear();
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ParameterTriggerValues copy constructor
    ///
    /// @brief Constructs the ParameterTriggerValues class, and copies the contents
    ///
    /// @param rhs  Object to copy from
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    PARAMETER_INLINE ParameterTriggerValues(const ParameterTriggerValues& rhs)
    {
        *this = rhs;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ParameterTriggerValues constructor
    ///
    /// @brief Constructs the ParameterTriggerValues class
    ///
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    PARAMETER_INLINE ~ParameterTriggerValues()
    {
        Clear();
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Copy operator
    ///
    /// @brief Copies the constents from another ParameterTriggerValues object
    ///
    /// @param rhs  Object to copy from
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ParameterTriggerValues& operator=(const ParameterTriggerValues& rhs)
    {
        if (&rhs != this)
        {
            Clear();
            ModePath = rhs.ModePath.c_str();
            Module   = rhs.Module.c_str();
            Pipeline = rhs.Pipeline.c_str();
            Values   = rhs.Values;
        }

        return *this;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Count
    ///
    /// @brief Returns the number of values
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    PARAMETER_INLINE UINT32 Count()
    {
        return Values.Count();
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Clear
    ///
    /// @brief Clears the ID values
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    PARAMETER_INLINE void Clear()
    {
        for (UINT32 i = 0; i < Values.Count(); i++)
        {
            PARAMETER_DELETE Values[i];
        }

        Values.Clear();
        CreateTime = clock();
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Find
    ///
    /// @brief Finds the trigger values for the id
    /// 
    /// @param id Identifier
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ParameterTriggerIDValues* Find(
        const CHAR* const id);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Add
    ///
    /// @brief Adds the trigger values for the id
    /// 
    /// @param id Identifier
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    PARAMETER_INLINE void Add(
        const CHAR* const             id,
        const ParameterCTValue* const values,
        UINT32 const                  count)
    {
        ParameterTriggerIDValues* idValues = PARAMETER_NEW ParameterTriggerIDValues(id, values, count);

        if (idValues != nullptr)
        {
            Values.Add(idValues);
        }
    }

    PARAMETER_STD_STRING ModePath;
    PARAMETER_STD_STRING Module;
    PARAMETER_STD_STRING Pipeline;
    PList<ParameterTriggerIDValues*> Values;
    clock_t CreateTime;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// class ParserCRC32
///
/// @brief Generates a 32 bit CRC
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ParserCRC32
{
public:

    // Returns the CRC value for a given buffer
    // If the buffer has the CRC appended, subtract it from the length
    static UINT32 GetCRC(
        const BYTE* const buffer,
        UINT32 const      length,
        UINT32 const      crcValue = 0);

    // Validates the CRC value of a buffer
    // CRC Value is expected to be the final 4 bytes of the buffer
    // The buffer must have the CRC appended, and the CRC must be included in the length
    static bool Validate(
        const BYTE* const     buffer,
        UINT32 const          length,
        IParameterLoggingAPI* logAPI);

private:
    static constexpr UINT32 TABLE_SIZE = 256U;
    static UINT32 m_table[TABLE_SIZE];
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// class ParserCRC32
///
/// @brief Generates a 64 bit CRC
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ParserCRC64
{
public:

    // Returns the CRC value for a given buffer
    // Length parameter is provided in case the buffer has the CRC appended
    // and should not be counted in the CRC check
    // If includeLength is true, the length will be included in the CRC value
    static UINT64 GetCRC(
        const BYTE* const buffer,
        UINT32 const      length,
        bool const        includeLength,
        UINT64 const      crcValue = 0);

    // Returns the CRC value for a given string + 32 bit length
    // Use this version if you already know the string length, do no include the nul terminator in the length
    static PARAMETER_INLINE UINT64 GetStringHash(
        const CHAR* const str,
        UINT32 const      length)
    {
        return GetCRC((const BYTE* const)str, length, true);
    }

    // Returns the CRC value for a given string + 32 bit length
    // Use this version if you don't already know the string length
    static PARAMETER_INLINE UINT64 GetStringHash(
        const CHAR* const str)
    {
        return GetCRC((const BYTE* const)str, (UINT32)PARAMETER_STRLEN(str), true);
    }

    // Validates the CRC value of a buffer
    // CRC Value is expected to be the final 8 bytes of the buffer
    static bool Validate(
        const BYTE* const     buffer,
        UINT32 const          length,
        bool const            includeLength,
        IParameterLoggingAPI* logAPI);

private:
    static constexpr UINT32 TABLE_SIZE = 256U;
    static UINT64 m_table[TABLE_SIZE];
};
PARAMETER_PACK_END
#endif // PARAMETERUTILS_H
