// Copyright (c) 2021 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 <OgnRandomBundlePointsDatabase.h>
#include <cstdlib>
#include <omni/graph/core/Type.h>

// This is the implementation of the OGN node defined in OgnRandomBundlePoints.ogn

namespace omni {
namespace graph {
using core::Type;
using core::BaseDataType;
using core::AttributeRole;
namespace test {

class OgnRandomBundlePoints
{
public:
    // Generate a bundle of "bundleSize" arrays of "pointCount" points at random locations within the bounding cube,
    // delineated by the corner points "minimum" and "maximum".
    static bool compute(OgnRandomBundlePointsDatabase& db)
    {
        const auto& minimum = db.inputs.minimum();
        GfVec3f rangeSize = db.inputs.maximum() - minimum;

        // No points mean nothing to generate
        const auto& pointCount = db.inputs.pointCount();
        if (pointCount == 0)
        {
            return true;
        }

        // Bundle size of zero means nothing to generate
        const auto& bundleSize = db.inputs.bundleSize();
        if (bundleSize == 0)
        {
            return true;
        }

        // Start with an empty bundle
        auto& outputBundle = db.outputs.bundle();
        outputBundle.clear();

        // Type definition for attributes that will be added to the bundle.
        Type pointsType{ BaseDataType::eFloat, 3, 1, AttributeRole::ePosition };

        // For each attribute to be added to the bundle create a unique array of random points
        for (size_t element=0; element < size_t(bundleSize); ++element)
        {
            std::string attributeName = std::string{"points"} + std::to_string(element);
            auto&& newAttribute = outputBundle.addAttribute(db.stringToToken(attributeName.c_str()), pointsType);
            auto pointsArray = newAttribute.get<float[][3]>();
            if (pointsArray)
            {
                pointsArray.resize(pointCount);
                for (auto& point : *pointsArray)
                {
                    point[0] = minimum[0] + static_cast<float>(rand()) /( static_cast<float>(RAND_MAX/(rangeSize[0])));
                    point[1] = minimum[1] + static_cast<float>(rand()) /( static_cast<float>(RAND_MAX/(rangeSize[1])));
                    point[2] = minimum[2] + static_cast<float>(rand()) /( static_cast<float>(RAND_MAX/(rangeSize[2])));
                }
            }
            else
            {
                db.logWarning("Could not get a reference to the constructed points attribute");
                return false;
            }
        }

        return true;
    }
};

REGISTER_OGN_NODE()

} // test
} // namespace graph
} // namespace omni
