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

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camxofflinedump.h
/// @brief Debug Dump related defines
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef CAMXOFFLINEDUMP_H
#define CAMXOFFLINEDUMP_H

#if defined (_WIN32)
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define OFFLINEDUMP_ERROR(...)   printf(__VA_ARGS__)
#if defined (OFFLINEDUMP_DEBUG)
#define OFFLINEDUMP_INFO(...)    printf(__VA_ARGS__)
#else
#define OFFLINEDUMP_INFO(...)
#endif

#elif defined (_LINUX)
#include <log.h>
#include <stdio.h>

#define OFFLINEDUMP_ERROR(fmt, args...)   ALOGE("%s():%d " fmt "\n", __func__, __LINE__, ##args)
#if defined (OFFLINEDUMP_DEBUG)
#define OFFLINEDUMP_INFO(fmt, args...)   ALOGI("%s():%d " fmt "\n", __func__, __LINE__, ##args)
#else
#define OFFLINEDUMP_INFO(fmt, args...)
#endif
#endif // (_WIN32) (_LINUX)

// Define memory allocation functions for whiner
// Using camxmem will produce circular dependency on libcamximageformatutils
#define OFFLINEDUMP_NEW new
#define OFFLINEDUMP_CALLOC calloc
#define OFFLINEDUMP_FREE free

#include <iostream>
#include <mutex>
#include <queue>
#include <string>

#include "camxdefs.h"
#include "chiofflinedumpinterface.h"

CAMX_NAMESPACE_BEGIN

/// @brief Buffer Info data structure
///        being passed into OfflineDump container
struct BufferInfo
{
   BOOL           bNeedFlush;          ///< When queue reaches flush threshold, set this flag to true
   UINT           numByteToWrite;      ///< The buffer size need to be written to file
   std::string    fileName;            ///< Filename for filesystem operation
   BYTE*          pData;               ///< Buffer
};

class OfflineDumpManager;

class OfflineDump
{
public:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// @brief The maximum different types of dumps supported
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static const UINT MaxSupportDumpTypeCount = static_cast<UINT>(OfflineDumpType::NUM_OF_TYPE);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// @brief Invalid Buffer Info Id
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static const INT InvalidBufferInfoId = -1;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DataDumpGeneric
    ///
    /// @brief  Dump into OfflineDump memory container
    ///
    /// @param  pFileName File name to dump into
    /// @param  pData     Pointer to data to dump
    /// @param  dumpSize  Size of data to dump
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_VISIBILITY_PUBLIC CamxResult DataDumpGeneric(
        const CHAR* pFileName,
        const BYTE* pData,
        UINT        dumpSize);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DataDump
    ///
    /// @brief  Dump into OfflineDump memory container with automatic stopping for request ids
    ///
    /// @param  pFileName File name to dump into
    /// @param  requestId Request id associated with this data
    /// @param  pData     Pointer to data to dump
    /// @param  dumpSize  Size of data to dump
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_VISIBILITY_PUBLIC CamxResult DataDump(
        const CHAR* pFileName,
        UINT64      requestId,
        const BYTE* pData,
        UINT        dumpSize);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Flush
    ///
    /// @brief  Flush a buffer into file system
    ///
    /// @param  bufferInfoId  Buffer Info Id to flush
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult Flush(
        INT bufferInfoId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// RequestBuffer
    ///
    /// @brief  Request new buffer for local thread
    ///
    /// @param  rpBuffer  Pass in local thread buffer pointer and assign a new one by OfflineDump
    ///
    /// @return bufferInfo ID registered within bufferInfo pool
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    INT RequestBuffer(
        BYTE* &rpBuffer);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// RequestFlushCurrentBuffer
    ///
    /// @brief  Request flush current buffer container
    ///
    /// @return VOID
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_VISIBILITY_PUBLIC VOID RequestFlushCurrentBuffer();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// RequestFlush
    ///
    /// @brief  Request to flush a buffer container
    ///
    /// @param  bufferInfoId  Id of buffer Info container that needs to be flushed
    ///
    /// @return VOID
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID RequestFlush(
        INT bufferInfoId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DisableOfflineDump
    ///
    /// @brief  Disable the OfflineDump
    ///
    /// @return VOID
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID DisableOfflineDump();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetOfflineDumpStatus
    ///
    /// @brief  Get the status of Offline Dump state
    ///
    /// @return Offline Dump Status
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_VISIBILITY_PUBLIC OfflineDumpStatus GetOfflineDumpStatus();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetStartFrameNum
    ///
    /// @brief  Set frameNum to start offline dump, also sets the frameNum to request id offset if required
    ///
    /// @param  frameNum  frame number to start dumping on, will refer to a specific requestId in CamX
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_VISIBILITY_PUBLIC VOID SetStartFrameNum(
        UINT64 frameNum);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetDumpStopFrameNum
    ///
    /// @brief  Set frameNum to stop offline dump, also sets the frameNum to request id offset if required
    ///
    /// @param  frameNum  frame number to stop dumping on, will refer to a specific requestId in CamX
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_VISIBILITY_PUBLIC VOID SetStopFrameNum(
        UINT64 frameNum);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetSettings
    ///
    /// @brief  This API will get override setting from CHI API
    ///
    /// @param  pSetting  Function pointer to Chi GetSettings
    ///
    /// @return result of this operation
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_VISIBILITY_PUBLIC BOOL GetSettings(
        PFNGETSETTINGS pSetting);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetFrameResetFlag
    ///
    /// @brief  This API will set frame number reset flag to set frame number to request id offset in Set[Start/Stop]FrameNum
    ///
    /// @param  flag BOOL TRUE if reset required
    ///
    /// @return result of this operation
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_VISIBILITY_PUBLIC VOID SetFrameResetFlag(
        BOOL flag);

    /// Constructor
    CAMX_VISIBILITY_PUBLIC OfflineDump(
        OfflineDumpManager* pManager,
        OfflineDumpType     type);

    /// Destructor
    ~OfflineDump();
private:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// AllocateBufferPool
    ///
    /// @brief  Allocate centralized memory pool
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult AllocateBufferPool();

    /// Do not support the copy constructor or assignment operator
    OfflineDump(const OfflineDump& rOfflineDump)             = delete;            ///< Disallow the copy constructor
    OfflineDump& operator= (const OfflineDump& rOfflineDump) = delete;            ///< Disallow assignment operator

    static thread_local BYTE* m_threadLocalBuffer[MaxSupportDumpTypeCount];        ///< Dump buffer container
    static thread_local INT   m_threadLocalBufferInfoId[MaxSupportDumpTypeCount];  ///< Buffer Info index
    static thread_local UINT  m_threadLocalBufferCurPos[MaxSupportDumpTypeCount];  ///< Current buffer cursor location

    OfflineDumpManager*       m_dumpManager;                      ///< Reference to singleton offline dump manager
    BOOL                      m_dumpEnable;                       ///< Dump enabled for this instance
    std::vector<BufferInfo>   m_bufferInfoPool;                   ///< Buffer info pool
    std::queue<INT>           m_availableBufferIdPool;            ///< Available memory id pool, queue of BufferInfo locations
    std::queue<INT>           m_bufferInfoIdFlushQueue;           ///< Queue of buffers that are ready to flush
    UINT32                    m_bufferSize;                       ///< Buffer size of this dump
    UINT32                    m_queueDepth;                       ///< Queue depth of this dump
    OfflineDumpStatus         m_offlineDumpStatus;                ///< OfflineDump status
    OfflineDumpType           m_offlineDumpType;                  ///< OfflineDump type
    std::mutex                m_pOfflineDumpLock;                 ///< Mutex to protect queue internal thread state
    UINT64                    m_startingReqId;                    ///< First request Id that is dumped in the set
    UINT64                    m_stoppingReqId;                    ///< Last request Id that is dumped in this set
    UINT64                    m_frameNumOffset;                   ///< Frame Number offset for triggers
    UINT32                    m_stopOffset;                       ///< How many requests to dump before stopping
                                                                  ///< Dump will start again after all frames are flushed
                                                                  ///< Dump will always be enabled when this value is 0
    BOOL                      m_bResetFrameOffset;                ///< Reset frame number offset in next capture request

};

CAMX_NAMESPACE_END
#endif
