/*
 * Copyright (c) 2018-2020, NVIDIA CORPORATION.  All rights reserved.
 *
 * NVIDIA CORPORATION and its licensors retain all intellectual property
 * and proprietary rights in and to this software, related documentation
 * and any modifications thereto.  Any use, reproduction, disclosure or
 * distribution of this software and related documentation without an express
 * license agreement from NVIDIA CORPORATION is strictly prohibited.
 */

#include <thread>
#include <queue>
#include <mutex>
#include <atomic>
#include <condition_variable>

#include "nvmedia_2d.h" // NvMedia2D Header for Blit
#include "nvmedia_idp.h" // NvMediaIDP Header  for Display

#include "NvSIPLClient.hpp" // NvSIPL Client header for input buffers
#include "CComposite.hpp" // Compositor base class

#ifndef CCOMPOSITENVSCI_HPP
#define CCOMPOSITENVSCI_HPP

#define NUM_PACKETS    6U
#define STREAMING_TIMEOUT 100000

using namespace nvsipl;

class CCompositeNvSci final : public CComposite
{
  typedef struct {
     uint32_t id;
     uint32_t row;
     uint32_t group;
     NvSciStreamBlock queue;
     NvSciStreamBlock consumer;
     NvSciStreamBlock upstream;
     NvSciSyncObj consumerSyncObj;
     NvSciSyncObj objFromProducer;
     std::vector<NvSciBufObj> sciBufObjs;    // one per packet
     std::vector<NvMediaImage*> imageList;   // one per packet
     NvSciSyncFence prefences[NUM_PACKETS];  // one per packet
     NvSciSyncFence postfences[NUM_PACKETS]; // one per packet
     NvSciStreamPacket packets[NUM_PACKETS]; // one per packet
     std::queue<uint32_t> vInputQueue;
  } ConsumerStream;

  public:
    // Destructor
    ~CCompositeNvSci()
    {
      if (m_bRunning) {
        this->Stop();
      }
    }

    // Initializes compositor
    SIPLStatus Init(uint32_t uDispID,
                    uint32_t uWinID,
                    uint32_t uWinDepth,
                    NvMediaRect *pRect,
                    NvSciBufModule bufModule,
                    NvSciSyncModule syncModule) override;

    // Registers a source and returns id assigned to it.
    SIPLStatus RegisterSource(uint32_t groupIndex,
                              uint32_t modIndex,
                              uint32_t outIndex,
                              bool isRaw,
                              uint32_t &id,
                              NvSciStreamBlock *consumer,
                              NvSciStreamBlock **upstream,
                              NvSciStreamBlock *queue,
                              QueueType queueType=QueueType_Fifo) override;

    SIPLStatus Deinit() override;

  protected:
    void ThreadFunc(void) override;

    bool CheckInputQueues(void) override;

    SIPLStatus PreSync(ConsumerStream *pStream, uint32_t index);
    SIPLStatus PostSync(ConsumerStream *pStream, uint32_t index);
    SIPLStatus ReleasePacket(ConsumerStream *pStream, uint32_t index);

    SIPLStatus CollectEvents(void);

    SIPLStatus SetupStreaming(void);

    SIPLStatus CloseStreaming(void);

    SIPLStatus DeleteImages(std::vector<NvMediaImage*>& images);

  private:
    // NvSci stuff
    NvSciSyncModule m_sciSyncModule {};
    NvSciBufModule m_sciBufModule {};
    ConsumerStream m_streams[NUM_OF_INPUTS] {};
    std::vector<ConsumerStream*> m_usedStreams;
};

#endif // CCOMPOSITENVSCI
