// Copyright (c) 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/Defines.h>
#include <carb/Types.h>
#include <carb/fastcache/FastCacheTypes.h>

namespace carb
{

namespace fastcache
{

struct FastCache
{
    CARB_PLUGIN_INTERFACE("carb::fastcache::FastCache", 0, 4)

    /// API for simple transform update

    // set transform for a usd prim to the fast cache
    // see FastCacheDirtyBits for options for dirty bits
    bool(CARB_ABI* setTransformF)(const pxr::SdfPath& primPath, const Transform& transform, FastCacheDirtyFlags dirtyFlags);

    // set 4x4 matrix directly for this prim
    bool(CARB_ABI* setWorldMatrixF)(const pxr::SdfPath& primPath, const Float4x4& mat, FastCacheDirtyFlags dirtyFlags);

    /// Optimized API for faster transform update
    /// each plugin should first call getCacheItemId to get integer id, then use set*ById functions below

    // path->index map may have changed, other plugins should update cache index (use getCacheItemId below)
    bool(CARB_ABI* indexMaybeDirty)(void);

    // index into transform cache buffer for the given prim path
    uint32_t(CARB_ABI* getCacheItemId)(const pxr::SdfPath& primPath);

    // optimized transform update using precomputed index
    bool(CARB_ABI* setTransformByIdF)(uint32_t, const Transform& transform, FastCacheDirtyFlags dirtyFlags);

    // Dead function - does nothing.
    bool(CARB_ABI* setWorldMatrixById)(uint32_t, const Float4x4& mat, FastCacheDirtyFlags dirtyFlags);


    // set transform for a usd instance to the fast cache
    // see FastCacheDirtyBits for options for dirty bits
    bool(CARB_ABI* setInstanceTransformF)(const pxr::SdfPath& instancerPath,
                                         const Transform& transform,
                                         uint32_t instanceIndex,
                                         FastCacheDirtyFlags dirtyFlags);

    // Dead function - does nothing.
    bool(CARB_ABI* setInstanceTransformBatch)(const pxr::SdfPath& instancerPath,
                                              const Transform* transform,
                                              uint32_t instanceCount,
                                              uint32_t instanceStartIndex);
    
    // Dead function - does nothing.
    bool(CARB_ABI* setInstancePositionBatch)(const pxr::SdfPath& instancerPath,
                                             const carb::Float3* position,
                                             uint32_t instanceCount,
                                             uint32_t instanceStartIndex);

    // get transform from fast cache for a usd prim
    bool(CARB_ABI* getTransformF)(const pxr::SdfPath& primPath, Transform& transform);

    bool(CARB_ABI* setPositionBuffer)(const pxr::SdfPath& primPath, const BufferDesc& buffer);

    bool(CARB_ABI* setNormalBuffer)(const pxr::SdfPath& primPath, const BufferDesc& binding);

    /*
    Sync with USD
    */
    void(CARB_ABI* blockUSDUpdate)(bool val);

    // Dead function - does nothing.
    void(CARB_ABI* enableSyncFastUpdate)(bool val);

    // Dead function - does nothing.
    bool(CARB_ABI* syncFastUpdate)();

    // Dead function - not implemented.
    void(CARB_ABI* handleAddedPrim)(const pxr::SdfPath& primPath);

    // Dead function - not implemented.
    void(CARB_ABI* handleChangedPrim)(const pxr::SdfPath& primPath);

    // Dead function - not implemented.
    void(CARB_ABI* handleRemovedPrim)(const pxr::SdfPath& primPath);

    // Dead function - not implemented.
    void(CARB_ABI* resyncPrimCacheMap)(void);

    // Dead function - not implemented.
    void(CARB_ABI* clearAll)(void);

    /// prim range cache

    // get size of a prim range (usd prim + all of its decendents)
    size_t(CARB_ABI* getPrimRangePathCount)(const pxr::SdfPath& primPath);

    // get subtree info (prim range)
    void(CARB_ABI* getPrimRangePaths)(const pxr::SdfPath& primPath, pxr::SdfPath* primRangePaths, size_t pathRangeSize);

    // Scatter the position data to corresponding instance possition slots routed by the indexMap
    bool(CARB_ABI* setInstancePositionF)(const pxr::SdfPath& instancerPath,
                                         const carb::Float3* position,
                                         const uint32_t* indexMap,
                                         const uint32_t& instanceCount);

    // Double versions of float functions
    bool(CARB_ABI* setTransformD)(const pxr::SdfPath& primPath, const TransformD& transform);
    bool(CARB_ABI* setWorldMatrixD)(const pxr::SdfPath& primPath, const Double4x4& mat);
    bool(CARB_ABI* setTransformByIdD)(uint32_t, const TransformD& transform);
    bool(CARB_ABI* setInstanceTransformD)(const pxr::SdfPath& instancerPath,
                                         const TransformD& transform,
                                         uint32_t instanceIndex);
    bool(CARB_ABI* getTransformD)(const pxr::SdfPath& primPath, TransformD& transform);
    bool(CARB_ABI* setInstancePositionD)(const pxr::SdfPath& instancerPath,
                                         const carb::Double3* position,
                                         const uint32_t* indexMap,
                                         const uint32_t& instanceCount);
    
    // Overloaded compatibility wrappers (float)
    bool setTransform(const pxr::SdfPath& primPath, const Transform& transform, FastCacheDirtyFlags dirtyFlags)
    {
        return setTransformF(primPath, transform, dirtyFlags);
    }
    bool setWorldMatrix(const pxr::SdfPath& primPath, const Float4x4& mat, FastCacheDirtyFlags dirtyFlags)
    {
        return setWorldMatrixF(primPath, mat, dirtyFlags);
    }
    bool setTransformById(uint32_t id, const Transform& transform, FastCacheDirtyFlags dirtyFlags)
    {
        return setTransformByIdF(id, transform, dirtyFlags);
    }
    bool setInstanceTransform(const pxr::SdfPath& instancerPath, const Transform& transform, uint32_t instanceIndex, FastCacheDirtyFlags dirtyFlags)
    {
        return setInstanceTransformF(instancerPath, transform, instanceIndex, dirtyFlags);
    }
    bool getTransform(const pxr::SdfPath& primPath, Transform& transform)
    {
        return getTransformF(primPath, transform);
    }
    bool setInstancePosition(const pxr::SdfPath& instancerPath, const carb::Float3* position, const uint32_t* indexMap, const uint32_t& instanceCount)
    {
        return setInstancePositionF(instancerPath, position, indexMap, instanceCount);
    }

    // Overloaded compatibility wrappers (double)
    bool setTransform(const pxr::SdfPath& primPath, const TransformD& transform, FastCacheDirtyFlags)
    {
        return setTransformD(primPath, transform);
    }
    bool setWorldMatrix(const pxr::SdfPath& primPath, const Double4x4& mat, FastCacheDirtyFlags)
    {
        return setWorldMatrixD(primPath, mat);
    }
    bool setTransformById(uint32_t id, const TransformD& transform, FastCacheDirtyFlags)
    {
        return setTransformByIdD(id, transform);
    }
    bool setInstanceTransform(const pxr::SdfPath& instancerPath, const TransformD& transform, uint32_t instanceIndex, FastCacheDirtyFlags)
    {
        return setInstanceTransformD(instancerPath, transform, instanceIndex);
    }
    bool getTransform(const pxr::SdfPath& primPath, TransformD& transform)
    {
        return getTransformD(primPath, transform);
    }
    bool setInstancePosition(const pxr::SdfPath& instancerPath, const carb::Double3* position, const uint32_t* indexMap, const uint32_t& instanceCount)
    {
        return setInstancePositionD(instancerPath, position, indexMap, instanceCount);
    }
};
} // namespace fastcache
} // namespace carb
