// 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.
//
#include <OgnTutorialArrayDataDatabase.h>
#include <algorithm>

class OgnTutorialArrayData
{
public:
    static bool compute(OgnTutorialArrayDataDatabase& db)
    {
        // For clarity get the attribute values into separate variables. The type definitions are included to
        // show exactly what data types are returned, though you should know that from your .ogn declaration.
        // It's sufficient to use "const auto" for inputs or "auto" for outputs.
        const float multiplier = db.inputs.multiplier();
        const ::ogn::const_array<float>& inputArray = db.inputs.original();
        const ::ogn::const_array<bool>& gateArray = db.inputs.gates();
        ::ogn::array<float>& outputArray = db.outputs.result();
        ::ogn::array<bool>& negativeValues = db.outputs.negativeValues();

        if (gateArray.size() != inputArray.size())
        {
            db.logWarning("Gate array size %zu should equal input array size %zu", gateArray.size(), inputArray.size());
            return false;
        }

        // Output array data has to be properly sized before filling as it will contain the same number
        // of elements as the input the size is already known. You could also do an assignment and modify the
        // output in place if that makes your algorithm more efficient:
        //     outputArray = inputArray;
        outputArray.resize(inputArray.size());
        negativeValues.resize(inputArray.size());

        // The attribute array data wrapper is compatible with the STL algorithms so computations can be
        // performed in a single std::algorithm call.
        std::transform(inputArray.begin(), inputArray.end(), gateArray.begin(), outputArray.begin(),
                       [multiplier](const float& value, const bool& gate) -> float
                       { return gate ? value * multiplier : value; });
        std::transform(outputArray.begin(), outputArray.end(), negativeValues.begin(),
                        [](const float& value) -> bool { return value < 0.0f; });

        // Regular iterators can also be applied
        int totalCharacters{ 0 };
        for (const auto& stringInput : db.inputs.info())
        {
            totalCharacters += int(std::strlen(db.tokenToString(stringInput)));
        }
        db.outputs.infoSize() = totalCharacters;
        return true;
    }
};

REGISTER_OGN_NODE()
