// Copyright (c) 2019-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.
//
#pragma once

#include <carb/Interface.h>
#include <carb/cudainterop/CudaInterop.h>
#include <carb/graphics/Graphics.h>
#include <carb/input/IInput.h>

namespace carb
{
namespace streamclient
{
class Context;
class Frame;

/**
 * Defines the streamclient interface.
 */
struct StreamClient
{
    CARB_PLUGIN_INTERFACE("carb::streamclient::StreamClient", 0, 2);

    /**
     * Creates stream client context.
     *
     * @param[in] graphics A pointer to a graphics interface to use.
     * @param[in] cudaInterop A pointer to a CUDA interop interface.
     * @param[in] device A pointer to a graphics device instance.
     * @return A pointer to the stream client context or nullptr.
     */
    Context*(CARB_ABI* createContext)(carb::graphics::Graphics* graphics,
                                      carb::cudainterop::CudaInterop* cudaInterop,
                                      carb::graphics::Device* device);

    /**
     * Destroys stream client context.
     *
     * @param[in] ctx A pointer to the stream client context.
     */
    void(CARB_ABI* destroyContext)(Context* ctx);

    /**
     * Starts stream client.
     *
     * @param[in] ctx A pointer to the stream client context.
     * @param[in] addr A pointer to a server IP address.
     * @param[in] port A server port number.
     * @return true if client started and connected successfully.
     */
    bool(CARB_ABI* startClient)(Context* ctx, const char* addr, uint16_t port);

    /**
     * Stops stream client.
     *
     * @param[in] ctx A pointer to the stream client context.
     */
    void(CARB_ABI* stopClient)(Context* ctx);

    /**
     * Pushes keyboard input event to a remote stream server.
     *
     * @param[in] ctx A pointer to the stream client context.
     * @param[in] evt A reference to the keyboard input event description.
     */
    void(CARB_ABI* pushKeyboardEvent)(Context* ctx, const carb::input::KeyboardEvent& evt);

    /**
     * Pushes mouse input event to a remote stream server.
     *
     * @param[in] ctx A pointer to the stream client context.
     * @param[in] evt A reference to the mouse input event description.
     */
    void(CARB_ABI* pushMouseEvent)(Context* ctx, const carb::input::MouseEvent& evt);

    /**
     * Pushes gamepad input event to a remote stream server.
     *
     * @param[in] ctx A pointer to the stream client context.
     * @param[in] evt A reference to the gamepad input event description.
     */
    void(CARB_ABI* pushGamepadEvent)(Context* ctx, const carb::input::GamepadEvent& evt);

    /**
     * Pushes window resize event to a remote stream server.
     *
     * @param[in] ctx A pointer to the stream client context.
     * @param[in] width New window width.
     * @param[in] height New window height.
     */
    void(CARB_ABI* pushResizeEvent)(Context* ctx, uint32_t width, uint32_t height);

    /**
     * Fetches video frame from streaming queue.
     *
     * @param[in] ctx A pointer to the stream client context.
     * @param[in] cmdList A pointer to the graphics command list to store readback and transformation commands.
     * @return A pointer to a video frame object or nullptr.
     *
     * The lifetime of each video frame object is managed inside stream client context, so caller don't have manage it
     * by self. The contents of video frame object becomes invalid after Nth call of fetch function.
     *
     * This method DOES NOT execute the command list, just adds readback, transformation and resource state transition
     * commands in it. So the actual frame content will be available only after the command list will be executed on the
     * caller side. Additionally, caller could add a fence in the same list after this method call to check when the
     * frame content will be ready. It is not nessesary if caller uses the same command list for rendering commands.
     */
    Frame*(CARB_ABI* fetchFrame)(Context* ctx, carb::graphics::CommandList* cmdList);

    /**
     * Renders video frame with built-in tiny renderer.
     *
     * @param[in] ctx A pointer to the stream client context.
     * @param[in] cmdList A pointer to the graphics command list to store rendering commands.
     * @param[in] frame A pointer to the video frame object or nullptr.
     *
     * This method DOES NOT render and DOES NOT execute the command list. It adds rendering commands in the
     * provided command list for subsequent execution on the caller side.
     */
    void(CARB_ABI* renderFrame)(Context* ctx, carb::graphics::CommandList* cmdList, Frame* frame);

    /**
     * Returns a pointer to texture object from a video frame object.
     *
     * @param[in] frame A pointer to a frame object obtained from fetchFrame call.
     * @return a pointer to texture object or nullptr.
     */
    carb::graphics::Texture*(CARB_ABI* getFrameTexture)(const Frame* frame);

    /**
     * Returns a pointer to texture descriptor object from a video frame object.
     *
     * @param[in] frame A pointer to a frame object obtained from fetchFrame call.
     * @return a pointer to texture descriptor object or nullptr.
     */
    carb::graphics::Descriptor*(CARB_ABI* getFrameDescriptor)(const Frame* frame);

    /**
     * Returns an extent of a video frame.
     *
     * @param[in] frame A pointer to a frame object obtained from fetchFrame call.
     * @return a pair of { width, height } for a given frame.
     */
    carb::Uint2(CARB_ABI* getFrameExtent)(const Frame* frame);
};
} // namespace streamclient
} // namespace carb
