////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2020-2021 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  chibinarylog.h
/// @brief Binary logging related definitions and prototypes
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef CHIBINARYLOG_H
#define CHIBINARYLOG_H

// NOWHINE FILE PR008: Custom compiler provided library next to its type declarations within a scoped preprocessor guard.
// NOWHINE FILE CP011: namespace is used to hide implementations for templated functions that need to be in a header file.
// NOWHINE FILE PR007b: standard library (cstring) needed for memcpy.
// NOWHINE FILE CP007: Templates needed for the feature.

#include <cstring>

#if defined (_LINUX)
#include "cdkutils.h"
#endif
#include "camxchiofflinelogger.h"
#include <cstdio>

// The Events we will be interested in logging
enum class LogEvent
{
    HAL3_Open,
    HAL3_ConfigSetup,
    HAL3_StreamInfo,
    HAL3_ProcessCaptureRequest,
    HAL3_ProcessCaptureResult,
    HAL3_BufferInfo,
    HAL3_FlushInfo,
    HAL3_Notify,
    FT2_Base_SubmitSessionRequest,
    FT2_Base_ProcessMessage,
    FT2_Base_ProcessResult,
    FT2_Base_SubmitRequest,
    FT2_FRO_Init,
    FT2_FRO_StateInfo,
    FT2_FRO_RequestInfo,
    FT2_FRO_ProcessSequenceInfo,
    FT2_FRO_PortDescriptorInfo,
    FT2_FRO_BufferInfo,
    FT2_FRO_OutputNotifiedPortInfo,
    FT2_FRO_ReleaseAckPortInfo,
    FT2_FRO_OutputReleaseInfo,
    FT2_FRO_Destroy,
    FT2_Graph_Init,
    FT2_Graph_FeatureInit,
    FT2_Graph_UpstreamFeatureRequest,
    FT2_Graph_ProcessMessage,
    FT2_Graph_ResultMetadataInfo,
    FT2_Graph_ExtSinkWalk,
    FT2_URO_StateInfo,
    FT2_URO_Init,
    ReqMap_AppFrameNum_to_CHXFrameNum,
    ReqMap_CHXFrameNum_to_pURO,
    ReqMap_pURO_to_pFRO,
    ReqMap_pFRO_to_CamX,
    ReqMap_CamXInfo,
    FenceCB_UnkownNode,
    FenceCB_Processed,
    Node_Initialize,
    Node_ProcessRequest,
    Node_EarlyMetadataDone,
    Node_PartialMetadataDone,
    Node_MetadataDone,
    Node_RequestIdDone,
    Node_SetupRequestOutputPort,
    Node_SetupRequestInputPort,
    CamXChi_CreateFence,
    Session_ProcessResult,
    Pipeline_PartialMetadataDone,
    Pipeline_MetadataDone,
    Pipeline_RequestIdDone,
    FT2_Pool_CreateInstance,
    ChiFenceCB_Processed,
    Pipeline_Initialize,
    LogicalCameraCamera3Device,
    LogicalCameraInfo,
    LogicalCameraDeviceInfo,
    LogicalCameraStreamMap,
    LogicalCameraSensorModes,
    LogicalCameraMappings,
    SystemEventData,
    ChiFeature2GraphDescDump,
    ChiFeature2InstanceDescDump,
    ChiFeature2DescriptorDump,
    ChiFeature2StageDescriptorDump,
    ChiFeature2SessionInfoDump,
    ChiFeature2PipelineInfoDump,
    ChiFeature2SessionDescriptorDump,
    ChiFeature2PipelineDescriptorDump,
    ChiFeature2PortDescriptorDump,
    ChiFeature2StreamIntentDescDump,
    ChiFeature2IdentifierDump,
    ChiFeature2InternalLinkDescDump,
    ChiFeature2InstancePropsDump,
    ChiFeature2PropertyDump,
    ChiFeature2GraphExtSrcLinkDescDump,
    ChiFeature2GlobalPortInstanceIdDump,
    ChiFeature2GraphInternalLinkDescDump,
    ChiFeature2GraphExtSinkLinkDescDump,
    ChiFeature2DependencyConfigDescriptorDump,
    ChiFeature2InputDependencyDump,
    ChiFeature2DependencyConfigInfoDump,
    ChiFeature2MetadataInfoDump,
    ChiFeature2PortBufferMetadataInfoDump,
    ChiFeature2InputConfigDump,
    ChiFeature2OutputConfigDump,
    EventDescriptor_Dump,
    HAL_Dump,
    F2_FRO_Dump,
    F2_FRO_RequestInfo_Dump,
    F2_FRO_RequestInfo_OutputNotified_Dump,
    F2_FRO_RequestInfo_OutputReleaseAcked_Dump,
    F2_FRO_SequenceInfo_Dump,
    F2_FRO_FIDMapping_Dump,
    F2_FRO_RequestInput_Dump,
    F2_FRO_Config_Dump,
    F2_FRO_Config_DumpInfo,
    F2_URO_Dump,
    F2_Base_Dump,
    F2_Base_DumpState,
    F2_Base_DumpState_InstanceProperty_Dump,
    F2_Base_DumpStageInfo,
    F2_Base_InstanceProperty_Dump,
    F2_Base_SeqData_Dump,
    F2_Base_Session_Dump,
    F2_Base_SessionData_Dump,
    F2_Base_PipelineData_Dump,
    F2_Base_InputPortData_Dump,
    F2_Base_InputPortStreamData_Dump,
    F2_Base_OutputPortData_Dump,
    F2_Base_OutputPortStreamData_Dump,
    F2_Wrapper_Dump,
    F2_Wrapper_InputMetadataTBM_Dump,
    F2_Wrapper_FGManager_Dump,
    F2_FeaturePool_Dump,
    F2_FeaturePool_DumpInfo,
    F2_FeaturePool_InstanceProperty_Dump,
    FeatureGraphManager_Dump,
    FeatureGraphManager_URODump,
    FeatureGraphManager_FGDump,
    FeatureGraphManager_FGSDump,
    FeatureGraphManager_StreamConfig_Dump,
    FeatureGraphManager_StreamConfig_DumpInfo,
    FeatureThreadManager_Dump,
    FeatureThreadManager_DumpInfo,
    FeatureGraph_Dump,
    FeatureGraph_FRODump,
    FeatureGraph_GraphNode_Dump,
    FeatureGraph_GraphNode_FRO_Dump,
    FeatureGraph_GraphNode_DownstreamMap_Dump,
    FeatureGraph_GraphNode_RequestTable_Dump,
    FeatureGraph_GraphNode_PortToInputLinkIndex_Dump,
    FeatureGraph_GraphNode_PortToOutputLinkIndexMap_Dump,
    FeatureGraph_GraphNode_ExtSrcLinkData_Dump,
    FeatureGraph_GraphNode_ExtSrcLinkData_Dependencies_Dump,
    FeatureGraph_GraphNode_ExtSrcLinkRequestTable_Dump,
    FeatureGraph_GraphNode_InternalLinkData_Dump,
    FeatureGraph_GraphNode_InternalLinkData_Dependencies_Dump,
    FeatureGraph_GraphNode_InternalLinkRequestTable_Dump,
    FeatureGraph_GraphNode_ExtSinkLinkData_Dump,
    FeatureGraph_GraphNode_ExtSinkLinkData_Dependencies_Dump,
    FeatureGraph_GraphNode_ExtSinkLinkRequestTable_Dump,
    FeatureGraph_GraphNode_FeatureGraphManagerCallbacks_Dump,
    FeatureGraph_GraphNode_ExtSrcPortIdToChiStream_Dump,
    FeatureGraph_GraphNode_ExtSinkPortIdToChiStream_Dump,
    FeatureGraph_GraphNode_UROStreamData_Dump,
    TargetBufferManager_Dump,
    TargetBufferManager_DumpInfo,
    TargetBufferManager_TargetList_Dump,
    TargetBufferManager_TargetList_MetadataBufferInfo_Dump,
    TargetBufferManager_TargetList_ExternalBufferInfo_Dump,
    TargetBufferManager_TargetList_InternalBufferInfo_Dump,
    TargetBufferManager_TargetList_InternalBufferInfo_DumpInfo,
    Usecase_Dump,
    CoreSession_Dump,
    CorePipeline_Dump,
    CorePipeline_DumpInfo,
    CorePipeline_PendingNodeInfo,
    CorePipeline_NodeInfo,
    FenceError_Dump,
    CoreNode_Dump,
    CoreNode_InputFence_Dump,
    CoreNode_InputPort_Dump,
    CoreNode_InputImageBuffer_Dump,
    CoreNode_OutputFence_Dump,
    CoreNode_OutputPort_Dump,
    CoreNode_OutputPort_DumpInfo,
    CoreNode_OutputImageBuffer_Dump,
    CoreNode_NodeFenceError_Dump,
    CoreNode_DumpNodeInfo_Dump,
    CoreNode_DumpNodeInfo_InputPortData_Dump,
    CoreNode_DumpNodeInfo_OutputPortData_Dump,
    CoreNode_DumpNodeInfo_OutputPortDataInfo_Dump,
    CoreNode_InputSourceBuffer_Dump,
    CoreNode_InputParentBuffer_Dump,
    CoreNode_OutputSinkBuffer_Dump,
    CoreNode_OutputNoSinkBuffer_Dump,
    CoreImageBuffer_Dump,
    CoreResultHolder_Dump,
    CoreResultHolder_DumpInfo,
    CoreResultHolder_NodesDump,
    CoreResultHolder_NodesDumpInfo,
    CoreResultHolder_NodesDataDump,
    CoreResultHolder_NodesInputDataDump,
    CoreResultHolder_NodesOutputDataDump,
    CoreHAL3Queue_Dump,
    CoreHAL3Queue_DumpInfo,
    CoreHAL3Queue_BatchedReqDump,
    CoreHAL3Queue_InputDataDump,
    CoreHAL3Queue_OutputDataDump,
    CoreHAL3Queue_MultiReqDump,
    CoreHAL3Queue_MultiReqDumpInfo,
    CoreDRQ_Dump,
    CoreDRQ_DependencyInfo,
    CoreDRQ_UnpublishedPropertyDump,
    CoreDRQ_CSLFencesInfo,
    CoreDRQ_CSLFenceDump,
    CoreDRQ_ChiFencesInfo,
    CoreDRQ_ChiFenceDump,
    CoreJobRegistry_Dump,
    CoreJobRegistry_DumpInfo,
    CoreImageBufferManager_Dump,
    CoreImageBufferManager_DumpInfo,
    CHIAssociationInfo_Dump,
    F2_HWMF_DumpInfo,
    F2_Realtime_DumpInfo,
    F2_RTMCX_DumpInfo,
    F2_HWMFHDR_DumpInfo,
    Pipeline_NodeOrdering,
    HALDevice_Config_Dump,
    HALDevice_Config_DumpInfo,
    ExtensionModule_Config_Dump,
    ChxUsecase_Config_Dump,
    AdvancedCameraUsecase_Config_Dump,
    AdvancedCameraUsecase_Config_DumpInfo,
    ChiMulticameraBase_Config_Dump,
    ChiMulticameraBase_Config_DumpInfo,
    UsecaseMultiCamera_Config_Dump,
    ChiFeature2PropertyDumpSTRING,
    ChiFeature2PropertyDumpUINT32,
    ChiFeature2PropertyDumpINT32,
    ChiFeature2PropertyDumpBOOL
};

// Indentation initialisation value for textual logging
static const UINT32 TEXTUAL_LOG_INDENT = 0;

// get some tools to work around the compiler intrinsic limitation (C-Style variadic arguments limitations)
#if defined __has_include
#if __has_include (<qc_binary_log.h>)
#define BINARY_LOG_COMPILING_WITH_SDLLVM
#endif
#endif

#ifdef  BINARY_LOG_COMPILING_WITH_SDLLVM
#include <qc_binary_log.h>
#define BINARY_LOG_COMPILING_WITH_SDLLVM
#define BINARY_LOG_TYPE_WRAPPER       __binary_log_struct
#define BINARY_LOG_WRAP_OBJECT(obj)   __binary_log_record(&obj)
#define BINARY_LOG_DUMP_PREAMBLE      __builtin_binary_log
// We are not compiling with SDLLVM, we need to provide our own version of qc_binary_log.h
#else

namespace details_binarylog {

    // An object wrapper to wrap non-trivial types (such as ones with a vtable) into a simple used defined type.
    template <typename T>
    struct TypeWrapper { T* x; };

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// WrapObject
    ///
    /// @brief  Return an instance of the pointer wrapper in a trivial type wrapper.
    ///
    /// @tparam T   The type that is wrapped in BINARY_LOG_TYPE_WRAPPER.
    ///
    /// @param ptr  The location of the wrapper object in memory.
    ///
    /// @return TypeWrapper<T> instance pointing to the object
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename T>
    TypeWrapper<T> WrapObject(T* ptr) {
        TypeWrapper<T> wrapped;
        wrapped.x = ptr;
        return wrapped;
    };
}

#define BINARY_LOG_TYPE_WRAPPER     TypeWrapper
#define BINARY_LOG_WRAP_OBJECT(obj) WrapObject(&obj)
#define BINARY_LOG_DUMP_PREAMBLE(...)

#endif // __snapdragon_llvm__

namespace details_binarylog {

    // Max size a binary log buffer can be in bytes.
    constexpr std::size_t MaxBinLogMsgSize = 256000;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CopyMem
    ///
    /// @brief  Perform a memcpy of the object wrapped in a BINARY_LOG_TYPE_WRAPPER<T>.
    ///
    /// @tparam T   The type that is wrapped in BINARY_LOG_TYPE_WRAPPER.
    ///
    /// @param out  The buffer we want to write the argument h to.
    /// @param h    The argument we want to log
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename T>
    constexpr void CopyMem(CHAR* out, const BINARY_LOG_TYPE_WRAPPER<T>& h) {
        memcpy(out, h.x, sizeof(T));
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CopyMem
    ///
    /// @brief  Perform a memcpy of the type given, applies to all types not wrapped in BINARY_LOG_TYPE_WRAPPER<T>.
    ///
    /// @tparam T   The type that we are writing to the stack buffer.
    ///
    /// @param out  The buffer we want to write the argument h to.
    /// @param h    The argument we want to log
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename T>
    constexpr void CopyMem(CHAR* out, const T& h) {
        memcpy(out, &h, sizeof(T));
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Dump Type
    ///
    /// @brief Given a type T, dump T with the BinaryLog__IGNORE event so the parsing scripts will know you are not declaring
    ///        an actual event
    ///
    /// @tparam T   The type that we are trying to dump a type descriptor for
    ///
    /// @param  w   The wrapper we want to wrap the type with
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename T>
    constexpr void DumpType(BINARY_LOG_TYPE_WRAPPER<T>&& t) {
#ifdef BINARY_LOG_COMPILING_WITH_SDLLVM
        enum CAMX_IGNORE_ENUM { BinaryLog__IGNORE };
        auto& x = t->x;
        BINARY_LOG_DUMP_PREAMBLE(CAMX_IGNORE_ENUM::BinaryLog__IGNORE, BINARY_LOG_WRAP_OBJECT(&x));
#else
        CAMX_UNREFERENCED_PARAM(t);
#endif
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Dump Type
    ///
    /// @brief Given a type T, dump T with the BinaryLog__IGNORE event so the parsing scripts will know you are not declaring
    ///        an actual event
    ///
    /// @tparam T   The type that we are trying to dump a type descriptor for
    ///
    /// @param  w   The object to use for type deduction
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename T>
    constexpr void DumpType(T&& x) {
#ifdef BINARY_LOG_COMPILING_WITH_SDLLVM
        enum CAMX_IGNORE_ENUM { BinaryLog__IGNORE };
        BINARY_LOG_DUMP_PREAMBLE(CAMX_IGNORE_ENUM::BinaryLog__IGNORE, x);
#else
        CAMX_UNREFERENCED_PARAM(x);
#endif
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ExtractBaseType
    ///
    /// @brief Identity function to return the object it was passed. Used as a base case for the type recursion used to remove
    ///        the arrays from the type.
    ///
    /// @tparam T   The type of obj
    ///
    /// @param  obj The object we want to return
    ///
    /// @return obj
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename T>
    constexpr auto ExtractBaseType(T obj) {
        return obj;
    };

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ExtractBaseType
    ///
    /// @brief Given a T*, this will return a T. Helpful in cases of array to ptr decay.
    ///
    /// Given T = int[1][2], f = ExtractBaseType.   f(T) = int
    ///
    /// @tparam T    The type that pObj points to
    ///
    /// @param  pObj The object we want to return
    ///
    /// @return obj
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename T>
    constexpr auto ExtractBaseType(T* pArr) {
        return ExtractBaseType(*pArr);
    };

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DumpArray
    ///
    /// @brief  Tell the compiler to dump out the type descriptor for the elements of the array as well
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename T, int N>
    constexpr void DumpArray(T(&arr)[N]) {
        using TT = decltype(ExtractBaseType(arr));
        TT* pDummy = nullptr;
        DumpType(*pDummy);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DumpArray
    ///
    /// @brief We have no arrays here so we dont need to do anything special
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename T>
    constexpr void DumpArray(T&& a) {
        CAMX_UNREFERENCED_PARAM(a);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// LogSize
    ///
    /// @brief  Perform a sizeof of the type given, applies to all types not wrapped in BINARY_LOG_TYPE_WRAPPER<T>.
    ///
    /// @tparam T   The type that we are getting the size for.
    ///
    /// @return size of the type T.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename T>
    struct LogSize {
        static constexpr auto value = sizeof(T);
    };

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// LogSize
    ///
    /// @brief  Perform a sizeof of the type wrapped in BINARY_LOG_TYPE_WRAPPER<T>.
    ///
    /// @tparam T   The type that we are getting the size for.
    ///
    /// @return size of the type wrapped in a binary log struct.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename T>
    struct LogSize<BINARY_LOG_TYPE_WRAPPER<T> > {
        static constexpr auto value = sizeof(T);
    };

    // Compiler error message shown when the max size is exceeded
#define MAX_BIN_LOG_MSG_SIZE_EXCEEDED_ERR "Maximum size of a log message (including metadata) is 256 Kilobytes"

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// TotalSize
    ///
    /// @brief  Calculates the size of a list of types.
    ///
    /// @tparam Head    The type that we are reading the size of currently.
    /// @tparam Tail    A paramater pack containing the rest of arguments we want to get the size for.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename Head, typename ...Tail>
    struct TotalSize {
        static constexpr std::size_t value = LogSize<Head>::value + TotalSize<Tail...>::value;
    };

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// TotalSize
    ///
    /// @brief  Calculates the size of a type.
    ///
    /// @tparam Head    The type that we are reading the size of currently.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename Head>
    struct TotalSize<Head> {
        static constexpr std::size_t value = LogSize<Head>::value;
    };

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FillBuffer
    ///
    /// @brief  Adds an element to the stack allocated buffer in WriteLog with the proper offset.
    ///
    /// @tparam Head    The type that we are writing to the stack buffer.
    ///
    /// @param out  The buffer we want to write the argument h to.
    /// @param h    The argument we want to log
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename Head>
    constexpr void FillBuffer(CHAR* out, Head&& h) {
        DumpArray(std::forward<Head>(h));
        CopyMem(out, std::forward<Head>(h));
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FillBuffer
    ///
    /// @brief  Adds an element to the stack allocated buffer in WriteLog with the proper offset and calculates the offset for
    ///         the next one.
    ///
    /// @tparam Head    The type that we are writing to the stack buffer.
    /// @tparam Tail    The rest of the types we want to log.
    ///
    /// @param out  The buffer we want to write the argument h to.
    /// @param h    The argument we want to log
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename Head, typename ...Tail>
    constexpr void FillBuffer(CHAR* out, Head&& h, Tail&&... args)
    {
        DumpArray(std::forward<Head>(h));
        CopyMem(out, std::forward<Head>(h));
        FillBuffer(out + LogSize<Head>::value, args...);
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// WriteLog
    ///
    /// @brief Stack allocate a buffer of an appropriate size, fill it with the arguments passed, then pass it to the logging
    /// infrastructure.
    ///
    /// @tparam Args  A parameter pack of the types we want to log.
    ///
    /// @param args   The argument we want to log.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename ...Args>
    constexpr void WriteLog(Args&&... args)
    {
        if (CamX::OfflineLogger::GetInstance(OfflineLoggerType::BINARY)->IsEnableOfflinelogger())
        {
            constexpr auto logMessageSize = TotalSize<Args...>::value;
            constexpr auto logBufferSize  = logMessageSize + LogSize<std::size_t>::value;
            static_assert(logBufferSize < MaxBinLogMsgSize, MAX_BIN_LOG_MSG_SIZE_EXCEEDED_ERR);
            CHAR buffer[logBufferSize];
            FillBuffer(buffer, logMessageSize, std::forward<Args>(args)...);
            CamX::OfflineLogger::GetInstance(OfflineLoggerType::BINARY)->AddLog(buffer, logBufferSize);
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// WriteLogToFile
    ///
    /// @brief Stack allocate a buffer of an appropriate size, fill it with the arguments passed, then pass it to the logging
    /// infrastructure.
    ///
    /// @tparam Args  A parameter pack of the types we want to log.
    ///
    /// @param file   The file we want to log to
    /// @param args   The argument we want to log.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename ...Args>
    constexpr void WriteLogToFile(std::FILE* file, Args&&... args)
    {
        constexpr auto logMessageSize = TotalSize<Args...>::value;
        constexpr auto logBufferSize  = logMessageSize + LogSize<std::size_t>::value;
        static_assert(logBufferSize < MaxBinLogMsgSize, MAX_BIN_LOG_MSG_SIZE_EXCEEDED_ERR);
        CHAR buffer[logBufferSize];
        FillBuffer(buffer, logMessageSize, std::forward<Args>(args)...);
        std::fwrite(buffer, logBufferSize, 1, file);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// BinaryLog Logs a message to the binary logging framework
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if (defined (_LINUX) && (!defined(LE_CAMERA)))
#define BINARY_LOG(evt, ...) \
{   \
    using namespace details_binarylog; \
    auto timestamp_nanoseconds = CdkUtils::GetNanosecondsSinceEpoch(); \
    auto threadID              = CdkUtils::GetThreadID(); \
    WriteLog(static_cast<UINT16>(evt), timestamp_nanoseconds, threadID, __VA_ARGS__); \
    BINARY_LOG_DUMP_PREAMBLE(evt, timestamp_nanoseconds, threadID, __VA_ARGS__); \
}
#else
#define BINARY_LOG(evt, ...) \
{} // Do nothing for windows
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// BinaryLog Logs a message to a file handle
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if (defined (_LINUX) && (!defined(LE_CAMERA)))
#define FILE_BINARY_LOG(fd, evt, ...) \
{   \
    if (0xFFFFFFFF != fd) \
    {   \
        using namespace details_binarylog; \
        auto timestamp_nanoseconds  = CdkUtils::GetNanosecondsSinceEpoch(); \
        auto threadID               = CdkUtils::GetThreadID(); \
        FILE* fileHandle            = reinterpret_cast<FILE*>(fd); \
        WriteLogToFile(fileHandle, static_cast<UINT16>(evt), timestamp_nanoseconds, threadID, __VA_ARGS__); \
        BINARY_LOG_DUMP_PREAMBLE(evt, timestamp_nanoseconds, threadID, __VA_ARGS__); \
    } \
}
#else
#define BINARY_LOG(evt, ...) \
{} // Do nothing for windows
#define FILE_BINARY_LOG(fd, evt, ...) \
{} // Do nothing for windows
#endif

// This is not needed outside of the details logic above.
#undef BINARY_LOG_TYPE_WRAPPER

#endif // CHIXBINARYLOG_H
