////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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 V5.5.1 (2411131018)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  aecxmeteringstatscalculator.cpp
/// @brief Auto-generated Chromatix parameter file
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "aecxmeteringstatscalculator.h"
#include "parametersetmanager.h"

AECXMETERINGSTATSCALCULATOR_NAMESPACE_BEGIN

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SetValue/GetValue Functions
/// Gets or sets the requested value
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool CalculatorGeneralParameters::GetValue(
    const CHAR* const __path,
    CHAR* const       __value,
    UINT32 const      __size)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    const UINT32 __pos = ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "weightTable1D") == 0)
    {
        ParameterUtils::DoubleToString((double)weightTable1D, __value, __size, 0);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "weightTable2D") == 0)
    {
        ParameterUtils::DoubleToString((double)weightTable2D, __value, __size, 0);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "subsampling") == 0)
    {
        ParameterUtils::DoubleToString((double)subsampling, __value, __size, 0);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "ROIID") == 0)
    {
        ParameterUtils::DoubleToString((double)ROIID, __value, __size, 0);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "rangeTrigger") == 0)
    {
        if (__index < rangeTriggerCount)
        {
            __result = rangeTrigger[__index].GetValue(&__path[__pos], __value, __size);
        }
    }

    return __result;
}

bool CalculatorGeneralParameters::SetValue(
    const CHAR* const __path,
    const CHAR* const __value)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    const UINT32 __pos = ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "weightTable1D") == 0)
    {
        const double dblValue = ParameterUtils::StringToDouble(__value, __result);
        if (__result)
        {
            weightTable1D = (UINT32)dblValue; 
        }
    }
    else if (PARAMETER_STRCMP(__name, "weightTable2D") == 0)
    {
        const double dblValue = ParameterUtils::StringToDouble(__value, __result);
        if (__result)
        {
            weightTable2D = (UINT32)dblValue; 
        }
    }
    else if (PARAMETER_STRCMP(__name, "subsampling") == 0)
    {
        const double dblValue = ParameterUtils::StringToDouble(__value, __result);
        if (__result)
        {
            subsampling = (UINT32)dblValue; 
        }
    }
    else if (PARAMETER_STRCMP(__name, "ROIID") == 0)
    {
        const double dblValue = ParameterUtils::StringToDouble(__value, __result);
        if (__result)
        {
            ROIID = (UINT32)dblValue; 
        }
    }
    else if (PARAMETER_STRCMP(__name, "rangeTrigger") == 0)
    {
        if (__index < rangeTriggerCount)
        {
            __result = rangeTrigger[__index].SetValue(&__path[__pos], __value);
        }
    }

    return __result;
}

bool CalculatorGeneralParameters::GetInfo(
    const CHAR* const           __path,
    PList<ParameterParserInfo>& __info)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    const UINT32 __pos = ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    // weightTable1D
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("weightTable1D", ParameterParserDataType::UInt32, (double)weightTable1D, 0));
    }
    else if (PARAMETER_STRCMP(__name, "weightTable1D") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::UInt32, (double)weightTable1D, 0));
    }

    // weightTable2D
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("weightTable2D", ParameterParserDataType::UInt32, (double)weightTable2D, 0));
    }
    else if (PARAMETER_STRCMP(__name, "weightTable2D") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::UInt32, (double)weightTable2D, 0));
    }

    // subsampling
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("subsampling", ParameterParserDataType::UInt32, (double)subsampling, 0));
    }
    else if (PARAMETER_STRCMP(__name, "subsampling") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::UInt32, (double)subsampling, 0));
    }

    // ROIID
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("ROIID", ParameterParserDataType::UInt32, (double)ROIID, 0));
    }
    else if (PARAMETER_STRCMP(__name, "ROIID") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::UInt32, (double)ROIID, 0));
    }

    // rangeTrigger
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("rangeTrigger", ParameterParserDataType::Structure, true, false, rangeTriggerCount));
    }
    else if (PARAMETER_STRCMP(__name, "rangeTrigger") == 0)
    {
        if (__index < rangeTriggerCount)
        {
            __result = rangeTrigger[__index].GetInfo(&__path[__pos], __info);
        }
        else
        {
            __result = true;
            __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::Structure, true, false, rangeTriggerCount));
        }
    }

    return __result;
}

bool CalculatorIntegerRangeType::GetValue(
    const CHAR* const __path,
    CHAR* const       __value,
    UINT32 const      __size)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "start") == 0)
    {
        ParameterUtils::DoubleToString((double)start, __value, __size, 0);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "end") == 0)
    {
        ParameterUtils::DoubleToString((double)end, __value, __size, 0);
        __result = true;
    }

    return __result;
}

bool CalculatorIntegerRangeType::SetValue(
    const CHAR* const __path,
    const CHAR* const __value)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "start") == 0)
    {
        const double dblValue = ParameterUtils::StringToDouble(__value, __result);
        if (__result)
        {
            start = (INT32)dblValue; 
        }
    }
    else if (PARAMETER_STRCMP(__name, "end") == 0)
    {
        const double dblValue = ParameterUtils::StringToDouble(__value, __result);
        if (__result)
        {
            end = (INT32)dblValue; 
        }
    }

    return __result;
}

bool CalculatorIntegerRangeType::GetInfo(
    const CHAR* const           __path,
    PList<ParameterParserInfo>& __info)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    // start
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("start", ParameterParserDataType::Int32, (double)start, 0));
    }
    else if (PARAMETER_STRCMP(__name, "start") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::Int32, (double)start, 0));
    }

    // end
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("end", ParameterParserDataType::Int32, (double)end, 0));
    }
    else if (PARAMETER_STRCMP(__name, "end") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::Int32, (double)end, 0));
    }

    return __result;
}

bool CalculatorStatsSelectionType::GetValue(
    const CHAR* const __path,
    CHAR* const       __value,
    UINT32 const      __size)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "channel1") == 0)
    {
        PARAMETER_STRCPY(__value, __size, channel1);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "channel2") == 0)
    {
        PARAMETER_STRCPY(__value, __size, channel2);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "channel3") == 0)
    {
        PARAMETER_STRCPY(__value, __size, channel3);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "channel4") == 0)
    {
        PARAMETER_STRCPY(__value, __size, channel4);
        __result = true;
    }

    return __result;
}

bool CalculatorStatsSelectionType::SetValue(
    const CHAR* const __path,
    const CHAR* const /*__value*/)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "channel1") == 0)
    {
        // Cannot modify strings, risk of memory leaks or corruption
    }
    else if (PARAMETER_STRCMP(__name, "channel2") == 0)
    {
        // Cannot modify strings, risk of memory leaks or corruption
    }
    else if (PARAMETER_STRCMP(__name, "channel3") == 0)
    {
        // Cannot modify strings, risk of memory leaks or corruption
    }
    else if (PARAMETER_STRCMP(__name, "channel4") == 0)
    {
        // Cannot modify strings, risk of memory leaks or corruption
    }

    return __result;
}

bool CalculatorStatsSelectionType::GetInfo(
    const CHAR* const           __path,
    PList<ParameterParserInfo>& __info)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    // channel1
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("channel1", ParameterParserDataType::String, channel1));
    }
    else if (PARAMETER_STRCMP(__name, "channel1") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::String, channel1));
    }

    // channel2
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("channel2", ParameterParserDataType::String, channel2));
    }
    else if (PARAMETER_STRCMP(__name, "channel2") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::String, channel2));
    }

    // channel3
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("channel3", ParameterParserDataType::String, channel3));
    }
    else if (PARAMETER_STRCMP(__name, "channel3") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::String, channel3));
    }

    // channel4
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("channel4", ParameterParserDataType::String, channel4));
    }
    else if (PARAMETER_STRCMP(__name, "channel4") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::String, channel4));
    }

    return __result;
}

bool StatsCalculatorType::GetValue(
    const CHAR* const __path,
    CHAR* const       __value,
    UINT32 const      __size)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    const UINT32 __pos = ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "calculatorID") == 0)
    {
        ParameterUtils::DoubleToString((double)calculatorID, __value, __size, 0);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "description") == 0)
    {
        PARAMETER_STRCPY(__value, __size, description);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "APISelection") == 0)
    {
        ParameterUtils::DoubleToString((double)(UINT32)APISelection, __value, __size, 0);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "statsSelection") == 0)
    {
        __result = statsSelection.GetValue(&__path[__pos], __value, __size);
    }
    else if (PARAMETER_STRCMP(__name, "expRatioHandle") == 0)
    {
        ParameterUtils::DoubleToString((double)(UINT32)expRatioHandle, __value, __size, 0);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "outputStorage") == 0)
    {
        __result = outputStorage.GetValue(&__path[__pos], __value, __size);
    }
    else if (PARAMETER_STRCMP(__name, "generalParameters") == 0)
    {
        __result = generalParameters.GetValue(&__path[__pos], __value, __size);
    }
    else if (PARAMETER_STRCMP(__name, "extensionArray") == 0)
    {
        if (__index < extensionArrayCount)
        {
            ParameterUtils::DoubleToString((double)extensionArray[__index], __value, __size);
            __result = true;
        }
        else
        {
            SIZE_T __valuePos = 0;
            for (UINT32 i = 0; i < extensionArrayCount; i++)
            {
                if (i > 0)
                {
                    PARAMETER_STRCAT(__value, __size, ",");
                    __valuePos = PARAMETER_STRLEN(__value);
                }
                ParameterUtils::DoubleToString((double)extensionArray[i], &__value[__valuePos], (INT32)(__size - __valuePos));
            }
            __result = true;
        }
    }

    return __result;
}

bool StatsCalculatorType::SetValue(
    const CHAR* const __path,
    const CHAR* const __value)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    const UINT32 __pos = ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "calculatorID") == 0)
    {
        const double dblValue = ParameterUtils::StringToDouble(__value, __result);
        if (__result)
        {
            calculatorID = (UINT32)dblValue; 
        }
    }
    else if (PARAMETER_STRCMP(__name, "description") == 0)
    {
        // Cannot modify strings, risk of memory leaks or corruption
    }
    else if (PARAMETER_STRCMP(__name, "APISelection") == 0)
    {
        const double dblValue = ParameterUtils::StringToDouble(__value, __result);
        if (__result)
        {
            APISelection = (CalculatorAPIType)(UINT32)dblValue; 
        }
    }
    else if (PARAMETER_STRCMP(__name, "statsSelection") == 0)
    {
        __result = statsSelection.SetValue(&__path[__pos], __value);
    }
    else if (PARAMETER_STRCMP(__name, "expRatioHandle") == 0)
    {
        const double dblValue = ParameterUtils::StringToDouble(__value, __result);
        if (__result)
        {
            expRatioHandle = (ExpRatioHandleType)(UINT32)dblValue; 
        }
    }
    else if (PARAMETER_STRCMP(__name, "outputStorage") == 0)
    {
        __result = outputStorage.SetValue(&__path[__pos], __value);
    }
    else if (PARAMETER_STRCMP(__name, "generalParameters") == 0)
    {
        __result = generalParameters.SetValue(&__path[__pos], __value);
    }
    else if (PARAMETER_STRCMP(__name, "extensionArray") == 0)
    {
        if (__index < extensionArrayCount)
        {
            const double dblValue = ParameterUtils::StringToDouble(__value, __result);
            if (__result)
            {
                extensionArray[__index] = (float)dblValue; 
            }
        }
        else
        {
            SIZE_T __valueLen = PARAMETER_STRLEN(__value);
            UINT32 __pos = 0;

            __index = 0;
            while (__pos < __valueLen && __index < extensionArrayCount)
            {
                CHAR __valueStr[MAX_SIZE];

                __pos += ParameterUtils::GetSubString(&__value[__pos], ',', __valueStr, MAX_SIZE);
                __pos++;

                const double dblValue = ParameterUtils::StringToDouble(__valueStr, __result);
                if (__result)
                {
                    extensionArray[__index] = (float)dblValue; 
                }
                __index++;
            }
            __result = true;
        }
    }

    return __result;
}

bool StatsCalculatorType::GetInfo(
    const CHAR* const           __path,
    PList<ParameterParserInfo>& __info)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    const UINT32 __pos = ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    // calculatorID
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("calculatorID", ParameterParserDataType::UInt32, (double)calculatorID, 0));
    }
    else if (PARAMETER_STRCMP(__name, "calculatorID") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::UInt32, (double)calculatorID, 0));
    }

    // description
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("description", ParameterParserDataType::String, description));
    }
    else if (PARAMETER_STRCMP(__name, "description") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::String, description));
    }

    // APISelection
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("APISelection", ParameterParserDataType::Enum, (double)(UINT32)APISelection, 0));
    }
    else if (PARAMETER_STRCMP(__name, "APISelection") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::Enum, (double)(UINT32)APISelection, 0));
    }

    // statsSelection
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("statsSelection", ParameterParserDataType::Structure));
    }
    else if (PARAMETER_STRCMP(__name, "statsSelection") == 0)
    {
        __result = statsSelection.GetInfo(&__path[__pos], __info);
    }

    // expRatioHandle
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("expRatioHandle", ParameterParserDataType::Enum, (double)(UINT32)expRatioHandle, 0));
    }
    else if (PARAMETER_STRCMP(__name, "expRatioHandle") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::Enum, (double)(UINT32)expRatioHandle, 0));
    }

    // outputStorage
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("outputStorage", ParameterParserDataType::Structure));
    }
    else if (PARAMETER_STRCMP(__name, "outputStorage") == 0)
    {
        __result = outputStorage.GetInfo(&__path[__pos], __info);
    }

    // generalParameters
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("generalParameters", ParameterParserDataType::Structure));
    }
    else if (PARAMETER_STRCMP(__name, "generalParameters") == 0)
    {
        __result = generalParameters.GetInfo(&__path[__pos], __info);
    }

    // extensionArray
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("extensionArray", ParameterParserDataType::Float, true, false, extensionArrayCount));
    }

    return __result;
}

bool AECXMeteringStatsCalculatorType::GetValue(
    const CHAR* const __path,
    CHAR* const       __value,
    UINT32 const      __size)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    const UINT32 __pos = ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "module_version") == 0)
    {
        __result = module_version.GetValue(&__path[__pos], __value, __size);
    }
    else if (PARAMETER_STRCMP(__name, "parameter_version") == 0)
    {
        __result = parameter_version.GetValue(&__path[__pos], __value, __size);
    }
    else if (PARAMETER_STRCMP(__name, "averageStatsCalculator") == 0)
    {
        __result = averageStatsCalculator.GetValue(&__path[__pos], __value, __size);
    }
    else if (PARAMETER_STRCMP(__name, "centerWeightedStatsCalculator") == 0)
    {
        __result = centerWeightedStatsCalculator.GetValue(&__path[__pos], __value, __size);
    }
    else if (PARAMETER_STRCMP(__name, "darkRatioStatsCalculator") == 0)
    {
        __result = darkRatioStatsCalculator.GetValue(&__path[__pos], __value, __size);
    }
    else if (PARAMETER_STRCMP(__name, "brightRatioStatsCalculator") == 0)
    {
        __result = brightRatioStatsCalculator.GetValue(&__path[__pos], __value, __size);
    }
    else if (PARAMETER_STRCMP(__name, "statsCalculators") == 0)
    {
        if (__index < statsCalculatorsCount)
        {
            __result = statsCalculators[__index].GetValue(&__path[__pos], __value, __size);
        }
    }

    return __result;
}

bool AECXMeteringStatsCalculatorType::SetValue(
    const CHAR* const __path,
    const CHAR* const __value)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    const UINT32 __pos = ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "module_version") == 0)
    {
        __result = module_version.SetValue(&__path[__pos], __value);
    }
    else if (PARAMETER_STRCMP(__name, "parameter_version") == 0)
    {
        __result = parameter_version.SetValue(&__path[__pos], __value);
    }
    else if (PARAMETER_STRCMP(__name, "averageStatsCalculator") == 0)
    {
        __result = averageStatsCalculator.SetValue(&__path[__pos], __value);
    }
    else if (PARAMETER_STRCMP(__name, "centerWeightedStatsCalculator") == 0)
    {
        __result = centerWeightedStatsCalculator.SetValue(&__path[__pos], __value);
    }
    else if (PARAMETER_STRCMP(__name, "darkRatioStatsCalculator") == 0)
    {
        __result = darkRatioStatsCalculator.SetValue(&__path[__pos], __value);
    }
    else if (PARAMETER_STRCMP(__name, "brightRatioStatsCalculator") == 0)
    {
        __result = brightRatioStatsCalculator.SetValue(&__path[__pos], __value);
    }
    else if (PARAMETER_STRCMP(__name, "statsCalculators") == 0)
    {
        if (__index < statsCalculatorsCount)
        {
            __result = statsCalculators[__index].SetValue(&__path[__pos], __value);
        }
    }

    return __result;
}

bool AECXMeteringStatsCalculatorType::GetInfo(
    const CHAR* const           __path,
    PList<ParameterParserInfo>& __info)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    const UINT32 __pos = ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    // module_version
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("module_version", ParameterParserDataType::Structure));
    }
    else if (PARAMETER_STRCMP(__name, "module_version") == 0)
    {
        __result = module_version.GetInfo(&__path[__pos], __info);
    }

    // parameter_version
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("parameter_version", ParameterParserDataType::Structure));
    }
    else if (PARAMETER_STRCMP(__name, "parameter_version") == 0)
    {
        __result = parameter_version.GetInfo(&__path[__pos], __info);
    }

    // averageStatsCalculator
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("averageStatsCalculator", ParameterParserDataType::Structure));
    }
    else if (PARAMETER_STRCMP(__name, "averageStatsCalculator") == 0)
    {
        __result = averageStatsCalculator.GetInfo(&__path[__pos], __info);
    }

    // centerWeightedStatsCalculator
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("centerWeightedStatsCalculator", ParameterParserDataType::Structure));
    }
    else if (PARAMETER_STRCMP(__name, "centerWeightedStatsCalculator") == 0)
    {
        __result = centerWeightedStatsCalculator.GetInfo(&__path[__pos], __info);
    }

    // darkRatioStatsCalculator
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("darkRatioStatsCalculator", ParameterParserDataType::Structure));
    }
    else if (PARAMETER_STRCMP(__name, "darkRatioStatsCalculator") == 0)
    {
        __result = darkRatioStatsCalculator.GetInfo(&__path[__pos], __info);
    }

    // brightRatioStatsCalculator
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("brightRatioStatsCalculator", ParameterParserDataType::Structure));
    }
    else if (PARAMETER_STRCMP(__name, "brightRatioStatsCalculator") == 0)
    {
        __result = brightRatioStatsCalculator.GetInfo(&__path[__pos], __info);
    }

    // statsCalculators
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("statsCalculators", ParameterParserDataType::Structure, true, false, statsCalculatorsCount));
    }
    else if (PARAMETER_STRCMP(__name, "statsCalculators") == 0)
    {
        if (__index < statsCalculatorsCount)
        {
            __result = statsCalculators[__index].GetInfo(&__path[__pos], __info);
        }
        else
        {
            __result = true;
            __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::Structure, true, false, statsCalculatorsCount));
        }
    }

    return __result;
}

bool AECXMeteringStatsCalculatorType::module_versionStruct::GetValue(
    const CHAR* const __path,
    CHAR* const       __value,
    UINT32 const      __size)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "major_revision") == 0)
    {
        ParameterUtils::DoubleToString((double)major_revision, __value, __size, 0);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "minor_revision") == 0)
    {
        ParameterUtils::DoubleToString((double)minor_revision, __value, __size, 0);
        __result = true;
    }
    else if (PARAMETER_STRCMP(__name, "incr_revision") == 0)
    {
        ParameterUtils::DoubleToString((double)incr_revision, __value, __size, 0);
        __result = true;
    }

    return __result;
}

bool AECXMeteringStatsCalculatorType::module_versionStruct::SetValue(
    const CHAR* const __path,
    const CHAR* const __value)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "major_revision") == 0)
    {
        const double dblValue = ParameterUtils::StringToDouble(__value, __result);
        if (__result)
        {
            major_revision = (INT32)dblValue; 
        }
    }
    else if (PARAMETER_STRCMP(__name, "minor_revision") == 0)
    {
        const double dblValue = ParameterUtils::StringToDouble(__value, __result);
        if (__result)
        {
            minor_revision = (INT32)dblValue; 
        }
    }
    else if (PARAMETER_STRCMP(__name, "incr_revision") == 0)
    {
        const double dblValue = ParameterUtils::StringToDouble(__value, __result);
        if (__result)
        {
            incr_revision = (INT32)dblValue; 
        }
    }

    return __result;
}

bool AECXMeteringStatsCalculatorType::module_versionStruct::GetInfo(
    const CHAR* const           __path,
    PList<ParameterParserInfo>& __info)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    // major_revision
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("major_revision", ParameterParserDataType::Int32, (double)major_revision, 0));
    }
    else if (PARAMETER_STRCMP(__name, "major_revision") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::Int32, (double)major_revision, 0));
    }

    // minor_revision
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("minor_revision", ParameterParserDataType::Int32, (double)minor_revision, 0));
    }
    else if (PARAMETER_STRCMP(__name, "minor_revision") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::Int32, (double)minor_revision, 0));
    }

    // incr_revision
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("incr_revision", ParameterParserDataType::Int32, (double)incr_revision, 0));
    }
    else if (PARAMETER_STRCMP(__name, "incr_revision") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::Int32, (double)incr_revision, 0));
    }

    return __result;
}

bool AECXMeteringStatsCalculatorType::parameter_versionStruct::GetValue(
    const CHAR* const __path,
    CHAR* const       __value,
    UINT32 const      __size)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "revision") == 0)
    {
        PARAMETER_STRCPY(__value, __size, revision);
        __result = true;
    }

    return __result;
}

bool AECXMeteringStatsCalculatorType::parameter_versionStruct::SetValue(
    const CHAR* const __path,
    const CHAR* const /*__value*/)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    if (PARAMETER_STRCMP(__name, "revision") == 0)
    {
        // Cannot modify strings, risk of memory leaks or corruption
    }

    return __result;
}

bool AECXMeteringStatsCalculatorType::parameter_versionStruct::GetInfo(
    const CHAR* const           __path,
    PList<ParameterParserInfo>& __info)
{
    constexpr SIZE_T MAX_SIZE = 129;
    CHAR   __name[MAX_SIZE] = "";
    UINT32 __index          = MAX_UINT;
    bool   __result         = false;

    ParameterUtils::GetVariable(__path, __name, __index, MAX_SIZE);

    // revision
    if (__name[0] == '\0')
    {
        __result = true;
        __info.Add(ParameterParserInfo("revision", ParameterParserDataType::String, revision));
    }
    else if (PARAMETER_STRCMP(__name, "revision") == 0)
    {
        __result = true;
        __info.Add(ParameterParserInfo(nullptr, ParameterParserDataType::String, revision));
    }

    return __result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Read enum value
/// @param entry [in] Symbol table entry
/// @param enumValue [out] Enum value to read
/// @param alignment [in] Symbol table byte alignment
/// @return true if successful
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ReadEnum_ExpRatioHandleType(
    ParameterFileSymbolTableEntry* const entry,
    ExpRatioHandleType& enumValue,
    BYTE const alignment)
{
    bool result {false};

    UINT32 uintValue {entry->ReadEnum(&result, alignment)};

    if (result)
    {
        switch (uintValue)
        {
        case static_cast<UINT32>(ExpRatioHandleType::DoNotHandle):
            enumValue = ExpRatioHandleType::DoNotHandle;
            result    = true;
            break;
        case static_cast<UINT32>(ExpRatioHandleType::ScaleShortThreshold):
            enumValue = ExpRatioHandleType::ScaleShortThreshold;
            result    = true;
            break;
        default:
            PARAMETER_LOG_ERROR(entry->SetManager, "Invalid value(% u) converting UINT32 to ExpRatioHandleType", uintValue);
            break;
        }
    }
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Read enum value
/// @param entry [in] Symbol table entry
/// @param enumValue [out] Enum value to read
/// @param alignment [in] Symbol table byte alignment
/// @return true if successful
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ReadEnum_CalculatorAPIType(
    ParameterFileSymbolTableEntry* const entry,
    CalculatorAPIType& enumValue,
    BYTE const alignment)
{
    bool result {false};

    UINT32 uintValue {entry->ReadEnum(&result, alignment)};

    if (result)
    {
        switch (uintValue)
        {
        case static_cast<UINT32>(CalculatorAPIType::API00Invalid):
            enumValue = CalculatorAPIType::API00Invalid;
            result    = true;
            break;
        case static_cast<UINT32>(CalculatorAPIType::API01GridWeightedAverage):
            enumValue = CalculatorAPIType::API01GridWeightedAverage;
            result    = true;
            break;
        case static_cast<UINT32>(CalculatorAPIType::API02GridSatRatiosAverage):
            enumValue = CalculatorAPIType::API02GridSatRatiosAverage;
            result    = true;
            break;
        case static_cast<UINT32>(CalculatorAPIType::API03GridRGBGAverage):
            enumValue = CalculatorAPIType::API03GridRGBGAverage;
            result    = true;
            break;
        case static_cast<UINT32>(CalculatorAPIType::API04HistWeightedAverage):
            enumValue = CalculatorAPIType::API04HistWeightedAverage;
            result    = true;
            break;
        case static_cast<UINT32>(CalculatorAPIType::API05HistLumaRangeAverage):
            enumValue = CalculatorAPIType::API05HistLumaRangeAverage;
            result    = true;
            break;
        case static_cast<UINT32>(CalculatorAPIType::API06HistPercentileRangeAverage):
            enumValue = CalculatorAPIType::API06HistPercentileRangeAverage;
            result    = true;
            break;
        case static_cast<UINT32>(CalculatorAPIType::API07RgbgDomainStatsCounter):
            enumValue = CalculatorAPIType::API07RgbgDomainStatsCounter;
            result    = true;
            break;
        case static_cast<UINT32>(CalculatorAPIType::API08ExtremeColorRgBgStatsRatio):
            enumValue = CalculatorAPIType::API08ExtremeColorRgBgStatsRatio;
            result    = true;
            break;
        case static_cast<UINT32>(CalculatorAPIType::API09GridStatsRoughness):
            enumValue = CalculatorAPIType::API09GridStatsRoughness;
            result    = true;
            break;
        case static_cast<UINT32>(CalculatorAPIType::API10HistPercentileRangeAverageHDR):
            enumValue = CalculatorAPIType::API10HistPercentileRangeAverageHDR;
            result    = true;
            break;
        case static_cast<UINT32>(CalculatorAPIType::API11):
            enumValue = CalculatorAPIType::API11;
            result    = true;
            break;
        case static_cast<UINT32>(CalculatorAPIType::API12):
            enumValue = CalculatorAPIType::API12;
            result    = true;
            break;
        default:
            PARAMETER_LOG_ERROR(entry->SetManager, "Invalid value(% u) converting UINT32 to CalculatorAPIType", uintValue);
            break;
        }
    }
    return result;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Default Constructor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
AECXMeteringStatsCalculatorTypeClass::AECXMeteringStatsCalculatorTypeClass(
    const CHAR* const name)
    : ParameterModule(name, MAJOR, MINOR, PATCH, nullptr)
{
    PARAMETER_INITIALIZE(SymbolTableID);
    PARAMETER_INITIALIZE(module_version);
    PARAMETER_INITIALIZE(parameter_version);
    PARAMETER_INITIALIZE(averageStatsCalculator);
    PARAMETER_INITIALIZE(centerWeightedStatsCalculator);
    PARAMETER_INITIALIZE(darkRatioStatsCalculator);
    PARAMETER_INITIALIZE(brightRatioStatsCalculator);
    PARAMETER_INITIALIZE(statsCalculatorsCount);
    PARAMETER_INITIALIZE(statsCalculators);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
AECXMeteringStatsCalculatorTypeClass::AECXMeteringStatsCalculatorTypeClass(
    const CHAR* const name,
    ModuleData* const moduleData)
    : ParameterModule(name, MAJOR, MINOR, PATCH, moduleData)
{
    PARAMETER_INITIALIZE(SymbolTableID);
    PARAMETER_INITIALIZE(module_version);
    PARAMETER_INITIALIZE(parameter_version);
    PARAMETER_INITIALIZE(averageStatsCalculator);
    PARAMETER_INITIALIZE(centerWeightedStatsCalculator);
    PARAMETER_INITIALIZE(darkRatioStatsCalculator);
    PARAMETER_INITIALIZE(brightRatioStatsCalculator);
    PARAMETER_INITIALIZE(statsCalculators);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Destructor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
AECXMeteringStatsCalculatorTypeClass::~AECXMeteringStatsCalculatorTypeClass()
{
    if (Loaded)
    {
        UnloadModule();
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// GetName
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const CHAR* AECXMeteringStatsCalculatorTypeClass::GetName(
    const CHAR* const type)
{
    const CHAR* name = type;
    CHAR temp[ParameterFileSymbolTableEntry::TYPE_LEN + 1];
    if (PARAMETER_STRCMP(type, ModuleData::GetType(temp, "aecxmeteringstatscalculator")) == 0)
    {
        name = "aecxmeteringstatscalculator";
    }
    return name;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Load CalculatorGeneralParameters
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool CalculatorGeneralParameters::Load(
    ParameterFileSymbolTableEntry* const entry,
    BYTE const alignment)
{
    bool result = true;

    PARAMETER_INITIALIZE(weightTable1D);
    PARAMETER_INITIALIZE(weightTable2D);
    PARAMETER_INITIALIZE(subsampling);
    PARAMETER_INITIALIZE(ROIID);
    PARAMETER_INITIALIZE(rangeTrigger);

    SYMBOL_TABLE_ENTRY_READ(entry, result, weightTable1D, alignment)
    SYMBOL_TABLE_ENTRY_READ(entry, result, weightTable2D, alignment)
    SYMBOL_TABLE_ENTRY_READ(entry, result, subsampling, alignment)
    SYMBOL_TABLE_ENTRY_READ(entry, result, ROIID, alignment)

    // Reading Array rangeTrigger from symbol table
    // Do not check result value here because the count value needs to be initialized in this block
    {
        rangeTriggerCount = 0;
        SYMBOL_TABLE_ENTRY_READ(entry, result, rangeTriggerCount, alignment)
        constexpr const CHAR* const file {__FILE__};
        constexpr INT32 line {LINE_CONST};
        ParameterFileSymbolTableEntry  pointerEntryCls;
        ParameterFileSymbolTableEntry* const pointerEntry = &pointerEntryCls;
        if (result)
        {
            result = entry->Table->ReadPointerEntry(pointerEntryCls, entry, alignment);
        }

        if (result)
        {
            rangeTriggerID = pointerEntry->ID;
            DupObjInfo* rangeTriggerDupInfo = pointerEntry->GetDupObject(rangeTriggerCount, file, line);
            if (rangeTriggerDupInfo != nullptr && rangeTriggerDupInfo->Object != nullptr)
            {
                rangeTrigger = (aecxglobalelements::TriggerSystemEndLevelStartEndType*)rangeTriggerDupInfo->Object;
                if (rangeTrigger == nullptr)
                {
                    if (rangeTriggerDupInfo->File != nullptr)
                    {
                        PARAMETER_LOG_ERROR(entry->SetManager, "rangeTrigger duplicate found but object is nullptr: %s:%d, RefCount: %d\n",
                            rangeTriggerDupInfo->File, rangeTriggerDupInfo->Line, rangeTriggerDupInfo->RefCount);
                    }
                    else
                    {
                        PARAMETER_LOG_ERROR(entry->SetManager, "rangeTrigger duplicate found but Object is nullptr: <nullptr file ptr>:%d, RefCount: %d\n",
                            rangeTriggerDupInfo->Line, rangeTriggerDupInfo->RefCount);
                    }
                }
            }

            if (rangeTrigger == nullptr)
            {
                if (result && rangeTriggerCount > 0)
                {
                    rangeTrigger = PARAMETER_NEW aecxglobalelements::TriggerSystemEndLevelStartEndType[rangeTriggerCount];
                    (void)pointerEntry->SetDupObject(rangeTrigger, rangeTriggerCount, file, line);
                }
                if (!result || rangeTrigger == nullptr)
                {
                    if (rangeTriggerCount > 0)
                    {
                        PARAMETER_LOG_ERROR(entry->SetManager, "Failed to allocate rangeTrigger\n");
                    }
                    rangeTriggerCount = 0;
                }
                for (UINT32 i = 0; result && i < rangeTriggerCount; i++)
                {
                    result = rangeTrigger[i].Load(pointerEntry, alignment);
                }
            }
        }
        if (rangeTrigger == nullptr)
        {
            rangeTriggerCount = 0;
        }
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Load CalculatorIntegerRangeType
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool CalculatorIntegerRangeType::Load(
    ParameterFileSymbolTableEntry* const entry,
    BYTE const alignment)
{
    bool result = true;

    PARAMETER_INITIALIZE(start);
    PARAMETER_INITIALIZE(end);

    SYMBOL_TABLE_ENTRY_READ(entry, result, start, alignment)
    SYMBOL_TABLE_ENTRY_READ(entry, result, end, alignment)

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Load CalculatorStatsSelectionType
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool CalculatorStatsSelectionType::Load(
    ParameterFileSymbolTableEntry* const entry,
    BYTE const alignment)
{
    bool result = true;

    PARAMETER_INITIALIZE(channel1);
    PARAMETER_INITIALIZE(channel2);
    PARAMETER_INITIALIZE(channel3);
    PARAMETER_INITIALIZE(channel4);


    // Reading String channel1 from symbol table
    {
        UINT32 count = 0;
        SYMBOL_TABLE_ENTRY_READ(entry, result, count, alignment)
        ParameterFileSymbolTableEntry stringPointerEntryCls;
        ParameterFileSymbolTableEntry* const stringPointerEntry = &stringPointerEntryCls;
        if (result)
        {
            result = entry->Table->ReadPointerEntry(stringPointerEntryCls, entry, alignment);
        }
        SYMBOL_TABLE_ENTRY_READ_STRING(stringPointerEntry, result, channel1, count, alignment)
    }

    // Reading String channel2 from symbol table
    {
        UINT32 count = 0;
        SYMBOL_TABLE_ENTRY_READ(entry, result, count, alignment)
        ParameterFileSymbolTableEntry stringPointerEntryCls;
        ParameterFileSymbolTableEntry* const stringPointerEntry = &stringPointerEntryCls;
        if (result)
        {
            result = entry->Table->ReadPointerEntry(stringPointerEntryCls, entry, alignment);
        }
        SYMBOL_TABLE_ENTRY_READ_STRING(stringPointerEntry, result, channel2, count, alignment)
    }

    // Reading String channel3 from symbol table
    {
        UINT32 count = 0;
        SYMBOL_TABLE_ENTRY_READ(entry, result, count, alignment)
        ParameterFileSymbolTableEntry stringPointerEntryCls;
        ParameterFileSymbolTableEntry* const stringPointerEntry = &stringPointerEntryCls;
        if (result)
        {
            result = entry->Table->ReadPointerEntry(stringPointerEntryCls, entry, alignment);
        }
        SYMBOL_TABLE_ENTRY_READ_STRING(stringPointerEntry, result, channel3, count, alignment)
    }

    // Reading String channel4 from symbol table
    {
        UINT32 count = 0;
        SYMBOL_TABLE_ENTRY_READ(entry, result, count, alignment)
        ParameterFileSymbolTableEntry stringPointerEntryCls;
        ParameterFileSymbolTableEntry* const stringPointerEntry = &stringPointerEntryCls;
        if (result)
        {
            result = entry->Table->ReadPointerEntry(stringPointerEntryCls, entry, alignment);
        }
        SYMBOL_TABLE_ENTRY_READ_STRING(stringPointerEntry, result, channel4, count, alignment)
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Load StatsCalculatorType
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool StatsCalculatorType::Load(
    ParameterFileSymbolTableEntry* const entry,
    BYTE const alignment)
{
    bool result = true;

    PARAMETER_INITIALIZE(calculatorID);
    PARAMETER_INITIALIZE(description);
    PARAMETER_INITIALIZE(APISelection);
    PARAMETER_INITIALIZE(statsSelection);
    PARAMETER_INITIALIZE(expRatioHandle);
    PARAMETER_INITIALIZE(outputStorage);
    PARAMETER_INITIALIZE(generalParameters);
    PARAMETER_INITIALIZE(extensionArray);

    SYMBOL_TABLE_ENTRY_READ(entry, result, calculatorID, alignment)

    // Reading String description from symbol table
    {
        UINT32 count = 0;
        SYMBOL_TABLE_ENTRY_READ(entry, result, count, alignment)
        ParameterFileSymbolTableEntry stringPointerEntryCls;
        ParameterFileSymbolTableEntry* const stringPointerEntry = &stringPointerEntryCls;
        if (result)
        {
            result = entry->Table->ReadPointerEntry(stringPointerEntryCls, entry, alignment);
        }
        SYMBOL_TABLE_ENTRY_READ_STRING(stringPointerEntry, result, description, count, alignment)
    }
    if (result)
    {
        result = aecxmeteringstatscalculator::ReadEnum_CalculatorAPIType(entry, APISelection, alignment);
    }
    if (result)
    {
        result = statsSelection.Load(entry, alignment);
    }
    if (result)
    {
        result = aecxmeteringstatscalculator::ReadEnum_ExpRatioHandleType(entry, expRatioHandle, alignment);
    }
    if (result)
    {
        result = outputStorage.Load(entry, alignment);
    }
    if (result)
    {
        result = generalParameters.Load(entry, alignment);
    }

    // Reading Array extensionArray from symbol table
    // Do not check result value here because the count value needs to be initialized in this block
    {
        extensionArrayCount = 0;
        SYMBOL_TABLE_ENTRY_READ(entry, result, extensionArrayCount, alignment)
        constexpr const CHAR* const file {__FILE__};
        constexpr INT32 line {LINE_CONST};
        ParameterFileSymbolTableEntry  pointerEntryCls;
        ParameterFileSymbolTableEntry* const pointerEntry = &pointerEntryCls;
        if (result)
        {
            result = entry->Table->ReadPointerEntry(pointerEntryCls, entry, alignment);
        }

        if (result)
        {
            extensionArrayID = pointerEntry->ID;
            DupObjInfo* extensionArrayDupInfo = pointerEntry->GetDupObject(extensionArrayCount, file, line);
            if (extensionArrayDupInfo != nullptr && extensionArrayDupInfo->Object != nullptr)
            {
                extensionArray = (float*)extensionArrayDupInfo->Object;
                if (extensionArray == nullptr)
                {
                    if (extensionArrayDupInfo->File != nullptr)
                    {
                        PARAMETER_LOG_ERROR(entry->SetManager, "extensionArray duplicate found but object is nullptr: %s:%d, RefCount: %d\n",
                            extensionArrayDupInfo->File, extensionArrayDupInfo->Line, extensionArrayDupInfo->RefCount);
                    }
                    else
                    {
                        PARAMETER_LOG_ERROR(entry->SetManager, "extensionArray duplicate found but Object is nullptr: <nullptr file ptr>:%d, RefCount: %d\n",
                            extensionArrayDupInfo->Line, extensionArrayDupInfo->RefCount);
                    }
                }
            }

            if (extensionArray == nullptr)
            {
                if (result && extensionArrayCount > 0)
                {
                    extensionArray = pointerEntry->ReadArray<float>(extensionArrayCount, alignment);
                    result = extensionArray != nullptr;
                }
                if (!result || extensionArray == nullptr)
                {
                    if (extensionArrayCount > 0)
                    {
                        PARAMETER_LOG_ERROR(entry->SetManager, "Failed to allocate extensionArray\n");
                    }
                    extensionArrayCount = 0;
                }
            }
        }
        if (extensionArray == nullptr)
        {
            extensionArrayCount = 0;
        }
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Load AECXMeteringStatsCalculatorType
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AECXMeteringStatsCalculatorType::Load(
    ParameterFileSymbolTableEntry* const entry,
    BYTE const alignment)
{
    bool result = true;

    PARAMETER_INITIALIZE(module_version);
    PARAMETER_INITIALIZE(parameter_version);
    PARAMETER_INITIALIZE(averageStatsCalculator);
    PARAMETER_INITIALIZE(centerWeightedStatsCalculator);
    PARAMETER_INITIALIZE(darkRatioStatsCalculator);
    PARAMETER_INITIALIZE(brightRatioStatsCalculator);
    PARAMETER_INITIALIZE(statsCalculators);

    result = module_version.Load(entry, alignment);
    if (result)
    {
        result = parameter_version.Load(entry, alignment);
    }
    if (result)
    {
        result = averageStatsCalculator.Load(entry, alignment);
    }
    if (result)
    {
        result = centerWeightedStatsCalculator.Load(entry, alignment);
    }
    if (result)
    {
        result = darkRatioStatsCalculator.Load(entry, alignment);
    }
    if (result)
    {
        result = brightRatioStatsCalculator.Load(entry, alignment);
    }

    // Reading Array statsCalculators from symbol table
    // Do not check result value here because the count value needs to be initialized in this block
    {
        statsCalculatorsCount = 0;
        SYMBOL_TABLE_ENTRY_READ(entry, result, statsCalculatorsCount, alignment)
        constexpr const CHAR* const file {__FILE__};
        constexpr INT32 line {LINE_CONST};
        ParameterFileSymbolTableEntry  pointerEntryCls;
        ParameterFileSymbolTableEntry* const pointerEntry = &pointerEntryCls;
        if (result)
        {
            result = entry->Table->ReadPointerEntry(pointerEntryCls, entry, alignment);
        }

        if (result)
        {
            statsCalculatorsID = pointerEntry->ID;
            DupObjInfo* statsCalculatorsDupInfo = pointerEntry->GetDupObject(statsCalculatorsCount, file, line);
            if (statsCalculatorsDupInfo != nullptr && statsCalculatorsDupInfo->Object != nullptr)
            {
                statsCalculators = (StatsCalculatorType*)statsCalculatorsDupInfo->Object;
                if (statsCalculators == nullptr)
                {
                    if (statsCalculatorsDupInfo->File != nullptr)
                    {
                        PARAMETER_LOG_ERROR(entry->SetManager, "statsCalculators duplicate found but object is nullptr: %s:%d, RefCount: %d\n",
                            statsCalculatorsDupInfo->File, statsCalculatorsDupInfo->Line, statsCalculatorsDupInfo->RefCount);
                    }
                    else
                    {
                        PARAMETER_LOG_ERROR(entry->SetManager, "statsCalculators duplicate found but Object is nullptr: <nullptr file ptr>:%d, RefCount: %d\n",
                            statsCalculatorsDupInfo->Line, statsCalculatorsDupInfo->RefCount);
                    }
                }
            }

            if (statsCalculators == nullptr)
            {
                if (result && statsCalculatorsCount > 0)
                {
                    statsCalculators = PARAMETER_NEW StatsCalculatorType[statsCalculatorsCount];
                    (void)pointerEntry->SetDupObject(statsCalculators, statsCalculatorsCount, file, line);
                }
                if (!result || statsCalculators == nullptr)
                {
                    if (statsCalculatorsCount > 0)
                    {
                        PARAMETER_LOG_ERROR(entry->SetManager, "Failed to allocate statsCalculators\n");
                    }
                    statsCalculatorsCount = 0;
                }
                for (UINT32 i = 0; result && i < statsCalculatorsCount; i++)
                {
                    result = statsCalculators[i].Load(pointerEntry, alignment);
                }
            }
        }
        if (statsCalculators == nullptr)
        {
            statsCalculatorsCount = 0;
        }
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Load module_versionStruct
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AECXMeteringStatsCalculatorType::module_versionStruct::Load(
    ParameterFileSymbolTableEntry* const entry,
    BYTE const alignment)
{
    bool result = true;

    PARAMETER_INITIALIZE(major_revision);
    PARAMETER_INITIALIZE(minor_revision);
    PARAMETER_INITIALIZE(incr_revision);

    SYMBOL_TABLE_ENTRY_READ(entry, result, major_revision, alignment)
    SYMBOL_TABLE_ENTRY_READ(entry, result, minor_revision, alignment)
    SYMBOL_TABLE_ENTRY_READ(entry, result, incr_revision, alignment)

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Load parameter_versionStruct
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AECXMeteringStatsCalculatorType::parameter_versionStruct::Load(
    ParameterFileSymbolTableEntry* const entry,
    BYTE const alignment)
{
    bool result = true;

    PARAMETER_INITIALIZE(revision);


    // Reading String revision from symbol table
    {
        UINT32 count = 0;
        SYMBOL_TABLE_ENTRY_READ(entry, result, count, alignment)
        ParameterFileSymbolTableEntry stringPointerEntryCls;
        ParameterFileSymbolTableEntry* const stringPointerEntry = &stringPointerEntryCls;
        if (result)
        {
            result = entry->Table->ReadPointerEntry(stringPointerEntryCls, entry, alignment);
        }
        SYMBOL_TABLE_ENTRY_READ_STRING(stringPointerEntry, result, revision, count, alignment)
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Unload CalculatorGeneralParameters
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CalculatorGeneralParameters::Unload(ParameterFileSymbolTable* const __table)
{
    if (__table != nullptr && __table->ReleaseDupObject(rangeTrigger))
    {
        PARAMETER_DELETE[] rangeTrigger;
    }
    rangeTrigger = nullptr;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Unload CalculatorStatsSelectionType
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CalculatorStatsSelectionType::Unload(ParameterFileSymbolTable* const __table)
{
    if (__table != nullptr && __table->ReleaseDupObject(channel1))
    {
        PARAMETER_DELETE[] channel1;
    }
    channel1 = nullptr;
    if (__table != nullptr && __table->ReleaseDupObject(channel2))
    {
        PARAMETER_DELETE[] channel2;
    }
    channel2 = nullptr;
    if (__table != nullptr && __table->ReleaseDupObject(channel3))
    {
        PARAMETER_DELETE[] channel3;
    }
    channel3 = nullptr;
    if (__table != nullptr && __table->ReleaseDupObject(channel4))
    {
        PARAMETER_DELETE[] channel4;
    }
    channel4 = nullptr;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Unload StatsCalculatorType
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void StatsCalculatorType::Unload(ParameterFileSymbolTable* const __table)
{
    if (__table != nullptr && __table->ReleaseDupObject(description))
    {
        PARAMETER_DELETE[] description;
    }
    description = nullptr;
    statsSelection.Unload(__table);
    generalParameters.Unload(__table);
    if (__table != nullptr && __table->ReleaseDupObject(extensionArray))
    {
        PARAMETER_DELETE[] extensionArray;
    }
    extensionArray = nullptr;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Unload AECXMeteringStatsCalculatorType
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void AECXMeteringStatsCalculatorType::Unload(ParameterFileSymbolTable* const __table)
{
    parameter_version.Unload(__table);
    averageStatsCalculator.Unload(__table);
    centerWeightedStatsCalculator.Unload(__table);
    darkRatioStatsCalculator.Unload(__table);
    brightRatioStatsCalculator.Unload(__table);
    for (UINT32 i = 0; i < statsCalculatorsCount; i++)
    {
        statsCalculators[i].Unload(__table);
    }
    if (__table != nullptr && __table->ReleaseDupObject(statsCalculators))
    {
        PARAMETER_DELETE[] statsCalculators;
    }
    statsCalculators = nullptr;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Unload parameter_versionStruct
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void AECXMeteringStatsCalculatorType::parameter_versionStruct::Unload(ParameterFileSymbolTable* const __table)
{
    if (__table != nullptr && __table->ReleaseDupObject(revision))
    {
        PARAMETER_DELETE[] revision;
    }
    revision = nullptr;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Release the ParameterModule object
/// Requires that this object was created via a ParameterSetManager::GetModule call
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void AECXMeteringStatsCalculatorType::Release()
{
    ((AECXMeteringStatsCalculatorTypeClass*)this)->Release();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Returns the ParameterModule::Modified value
/// The Modified value is incremented when the module's data or pointer values change
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT32 AECXMeteringStatsCalculatorType::GetModified()
{
    return ((AECXMeteringStatsCalculatorTypeClass*)this)->Modified;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Create module, and return a new object
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ParameterModule* AECXMeteringStatsCalculatorTypeClass::Create(
    ModuleData*    moduleData,
    DefaultModule* const defModule) const
{
    AECXMeteringStatsCalculatorTypeClass* cls = nullptr;

    if (PARAMETER_STRCMP(Type, moduleData->Type) == 0 && Version.Value == moduleData->Version.Value)
    {
        const UINT32 id = moduleData->DuplicateID > 0 ? moduleData->DuplicateID : moduleData->ID;

        ParameterModule* const module = defModule->Find(id);
        if (module != nullptr)
        {
            cls = (AECXMeteringStatsCalculatorTypeClass*)module;
        }
        else
        {
            cls = PARAMETER_NEW AECXMeteringStatsCalculatorTypeClass(GetName(moduleData->Type), moduleData);
            cls->SymbolTableID = id;
            defModule->AddModule((ParameterModule*)cls);
        }
    }
    else if (Version.Value != moduleData->Version.Value)
    {
        PARAMETER_LOG_ERROR(moduleData->SetManager, "Unable to create AECXMeteringStatsCalculatorTypeClass, binary version (%lld) does not match source version (%lld)\n",
            moduleData->Version.Value, Version.Value);
    }
    else
    {
        PARAMETER_LOG_ERROR(moduleData->SetManager, "Unable to create AECXMeteringStatsCalculatorTypeClass, binary name (%s) does not match source name (%s)\n",
            moduleData->Type, Type);
    }

    return (ParameterModule*)cls;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Load module data, return true is successful
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AECXMeteringStatsCalculatorTypeClass::LoadModule(
    ParameterFileSymbolTable* const table)
{
    bool result = true;

    if (!Loaded)
    {
        BYTE const alignment = table->Alignment;
        AECXMeteringStatsCalculatorTypeClass* const cls = this;

        ParameterFileSymbolTableEntry  entryObj;
        ParameterFileSymbolTableEntry* const entry = &entryObj;
        // With EzTune enabled, the unused upper byte of SymbolTableID value can change, so clear it
        result = table->Find(entryObj, SymbolTableID & 0x00ffffff);

        if (!result)
        {
            PARAMETER_LOG_ERROR(entry->SetManager, "AECXMeteringStatsCalculatorTypeClass::LoadModule Failed to find module ID (%d) in Symbol Table\n", SymbolTableID);
        }

        if (result)
        {
            result = cls->Load(entry, alignment);
        }
        Modified++;
        Loaded = true;
    }

    if (!result)
    {
        /// Module failed to fully load, unload it
        UnloadModule();
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Unload module data
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void AECXMeteringStatsCalculatorTypeClass::UnloadModule()
{
    if (Loaded)
    {
        if (Data != nullptr && Data->SymbolTable != nullptr)
        {
            Unload(Data->SymbolTable);
        }
        else
        {
            PARAMETER_LOG_ERROR(Data != nullptr ? Data->SetManager : nullptr, "UnloadModule %s called with nullptr "
                "Data->SymbolTable object\n", Name);
            Unload(nullptr);
        }
        Loaded = false;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// /// Release the ParameterModule object
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void AECXMeteringStatsCalculatorTypeClass::Release()
{
    ParameterModule::Release();
}

AECXMETERINGSTATSCALCULATOR_NAMESPACE_END
