// 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 <OgnTestAllDataTypesCarbDatabase.h>

namespace omni {
namespace graph {
using core::ogn::array;
using core::ogn::const_array;
using core::ogn::string;
using core::ogn::const_string;
namespace test {

// Helper template that reduces the testing code while hardcoding to the expected types.
// This version is for types that are directly assignable.
template <typename DataType, typename ConstDataType, typename std::enable_if_t<std::is_assignable<DataType, ConstDataType>::value, int> = 0>
void assign(DataType& dst, ConstDataType& src)
{
    dst = src;
}
// This version is for types that cannot be assigned. memcpy works for them since we require types to be byte-compatible
template <typename DataType, typename ConstDataType, typename std::enable_if_t<! std::is_assignable<DataType, ConstDataType>::value, int> = 0>
void assign(DataType& dst, ConstDataType& src)
{
    memcpy(&dst, &src, sizeof(DataType));
}

class OgnTestAllDataTypesCarb
{
public:
    static bool compute(OgnTestAllDataTypesCarbDatabase& db)
    {
        if (db.inputs.doNotCompute())
        {
            return true;
        }
        assign<bool, const bool>(db.outputs.a_bool(), db.inputs.a_bool());
        assign<array<bool>, const const_array<bool>>(db.outputs.a_bool_array(), db.inputs.a_bool_array());

        assign<carb::ColorRgbDouble, const carb::ColorRgbDouble>(db.outputs.a_colord_3(), db.inputs.a_colord_3());
        assign<carb::ColorRgbaDouble, const carb::ColorRgbaDouble>(db.outputs.a_colord_4(), db.inputs.a_colord_4());
        assign<carb::ColorRgb, const carb::ColorRgb>(db.outputs.a_colorf_3(), db.inputs.a_colorf_3());
        assign<carb::ColorRgba, const carb::ColorRgba>(db.outputs.a_colorf_4(), db.inputs.a_colorf_4());
        assign<pxr::GfVec3h, const pxr::GfVec3h>(db.outputs.a_colorh_3(), db.inputs.a_colorh_3());
        assign<pxr::GfVec4h, const pxr::GfVec4h>(db.outputs.a_colorh_4(), db.inputs.a_colorh_4());
        assign<array<carb::ColorRgbDouble>, const const_array<carb::ColorRgbDouble>>(db.outputs.a_colord_3_array(), db.inputs.a_colord_3_array());
        assign<array<carb::ColorRgbaDouble>, const const_array<carb::ColorRgbaDouble>>(db.outputs.a_colord_4_array(), db.inputs.a_colord_4_array());
        assign<array<carb::ColorRgb>, const const_array<carb::ColorRgb>>(db.outputs.a_colorf_3_array(), db.inputs.a_colorf_3_array());
        assign<array<carb::ColorRgba>, const const_array<carb::ColorRgba>>(db.outputs.a_colorf_4_array(), db.inputs.a_colorf_4_array());
        assign<array<pxr::GfVec3h>, const const_array<pxr::GfVec3h>>(db.outputs.a_colorh_3_array(), db.inputs.a_colorh_3_array());
        assign<array<pxr::GfVec4h>, const const_array<pxr::GfVec4h>>(db.outputs.a_colorh_4_array(), db.inputs.a_colorh_4_array());

        assign<double, const double>(db.outputs.a_double(), db.inputs.a_double());
        assign<carb::Double2, const carb::Double2>(db.outputs.a_double_2(), db.inputs.a_double_2());
        assign<carb::Double3, const carb::Double3>(db.outputs.a_double_3(), db.inputs.a_double_3());
        assign<carb::Double4, const carb::Double4>(db.outputs.a_double_4(), db.inputs.a_double_4());
        assign<array<double>, const const_array<double>>(db.outputs.a_double_array(), db.inputs.a_double_array());
        assign<array<carb::Double2>, const const_array<carb::Double2>>(db.outputs.a_double_2_array(), db.inputs.a_double_2_array());
        assign<array<carb::Double3>, const const_array<carb::Double3>>(db.outputs.a_double_3_array(), db.inputs.a_double_3_array());
        assign<array<carb::Double4>, const const_array<carb::Double4>>(db.outputs.a_double_4_array(), db.inputs.a_double_4_array());

        assign<uint32_t, const uint32_t>(db.outputs.a_execution(), db.inputs.a_execution());

        assign<float, const float>(db.outputs.a_float(), db.inputs.a_float());
        assign<carb::Float2, const carb::Float2>(db.outputs.a_float_2(), db.inputs.a_float_2());
        assign<carb::Float3, const carb::Float3>(db.outputs.a_float_3(), db.inputs.a_float_3());
        assign<carb::Float4, const carb::Float4>(db.outputs.a_float_4(), db.inputs.a_float_4());
        assign<array<float>, const const_array<float>>(db.outputs.a_float_array(), db.inputs.a_float_array());
        assign<array<carb::Float2>, const const_array<carb::Float2>>(db.outputs.a_float_2_array(), db.inputs.a_float_2_array());
        assign<array<carb::Float3>, const const_array<carb::Float3>>(db.outputs.a_float_3_array(), db.inputs.a_float_3_array());
        assign<array<carb::Float4>, const const_array<carb::Float4>>(db.outputs.a_float_4_array(), db.inputs.a_float_4_array());

        assign<pxr::GfMatrix4d, const pxr::GfMatrix4d>(db.outputs.a_frame_4(), db.inputs.a_frame_4());
        assign<array<pxr::GfMatrix4d>, const const_array<pxr::GfMatrix4d>>(db.outputs.a_frame_4_array(), db.inputs.a_frame_4_array());

        assign<pxr::GfHalf, const pxr::GfHalf>(db.outputs.a_half(), db.inputs.a_half());
        assign<pxr::GfVec2h, const pxr::GfVec2h>(db.outputs.a_half_2(), db.inputs.a_half_2());
        assign<pxr::GfVec3h, const pxr::GfVec3h>(db.outputs.a_half_3(), db.inputs.a_half_3());
        assign<pxr::GfVec4h, const pxr::GfVec4h>(db.outputs.a_half_4(), db.inputs.a_half_4());
        assign<array<pxr::GfHalf>, const const_array<pxr::GfHalf>>(db.outputs.a_half_array(), db.inputs.a_half_array());
        assign<array<pxr::GfVec2h>, const const_array<pxr::GfVec2h>>(db.outputs.a_half_2_array(), db.inputs.a_half_2_array());
        assign<array<pxr::GfVec3h>, const const_array<pxr::GfVec3h>>(db.outputs.a_half_3_array(), db.inputs.a_half_3_array());
        assign<array<pxr::GfVec4h>, const const_array<pxr::GfVec4h>>(db.outputs.a_half_4_array(), db.inputs.a_half_4_array());

        assign<int, const int>(db.outputs.a_int(), db.inputs.a_int());
        assign<carb::Int2, const carb::Int2>(db.outputs.a_int_2(), db.inputs.a_int_2());
        assign<carb::Int3, const carb::Int3>(db.outputs.a_int_3(), db.inputs.a_int_3());
        assign<carb::Int4, const carb::Int4>(db.outputs.a_int_4(), db.inputs.a_int_4());
        assign<array<int>, const const_array<int>>(db.outputs.a_int_array(), db.inputs.a_int_array());
        assign<array<carb::Int2>, const const_array<carb::Int2>>(db.outputs.a_int_2_array(), db.inputs.a_int_2_array());
        assign<array<carb::Int3>, const const_array<carb::Int3>>(db.outputs.a_int_3_array(), db.inputs.a_int_3_array());
        assign<array<carb::Int4>, const const_array<carb::Int4>>(db.outputs.a_int_4_array(), db.inputs.a_int_4_array());

        assign<int64_t, const int64_t>(db.outputs.a_int64(), db.inputs.a_int64());
        assign<array<int64_t>, const const_array<int64_t>>(db.outputs.a_int64_array(), db.inputs.a_int64_array());

        assign<pxr::GfMatrix2d, const pxr::GfMatrix2d>(db.outputs.a_matrixd_2(), db.inputs.a_matrixd_2());
        assign<pxr::GfMatrix3d, const pxr::GfMatrix3d>(db.outputs.a_matrixd_3(), db.inputs.a_matrixd_3());
        assign<pxr::GfMatrix4d, const pxr::GfMatrix4d>(db.outputs.a_matrixd_4(), db.inputs.a_matrixd_4());
        assign<array<pxr::GfMatrix2d>, const const_array<pxr::GfMatrix2d>>(db.outputs.a_matrixd_2_array(), db.inputs.a_matrixd_2_array());
        assign<array<pxr::GfMatrix3d>, const const_array<pxr::GfMatrix3d>>(db.outputs.a_matrixd_3_array(), db.inputs.a_matrixd_3_array());
        assign<array<pxr::GfMatrix4d>, const const_array<pxr::GfMatrix4d>>(db.outputs.a_matrixd_4_array(), db.inputs.a_matrixd_4_array());

        assign<carb::Double3, const carb::Double3>(db.outputs.a_normald_3(), db.inputs.a_normald_3());
        assign<carb::Float3, const carb::Float3>(db.outputs.a_normalf_3(), db.inputs.a_normalf_3());
        assign<pxr::GfVec3h, const pxr::GfVec3h>(db.outputs.a_normalh_3(), db.inputs.a_normalh_3());
        assign<array<carb::Double3>, const const_array<carb::Double3>>(db.outputs.a_normald_3_array(), db.inputs.a_normald_3_array());
        assign<array<carb::Float3>, const const_array<carb::Float3>>(db.outputs.a_normalf_3_array(), db.inputs.a_normalf_3_array());
        assign<array<pxr::GfVec3h>, const const_array<pxr::GfVec3h>>(db.outputs.a_normalh_3_array(), db.inputs.a_normalh_3_array());

        assign<uint64_t, const uint64_t>(db.outputs.a_objectId(), db.inputs.a_objectId());
        assign<array<uint64_t>, const const_array<uint64_t>>(db.outputs.a_objectId_array(), db.inputs.a_objectId_array());

        assign<carb::Double3, const carb::Double3>(db.outputs.a_pointd_3(), db.inputs.a_pointd_3());
        assign<carb::Float3, const carb::Float3>(db.outputs.a_pointf_3(), db.inputs.a_pointf_3());
        assign<pxr::GfVec3h, const pxr::GfVec3h>(db.outputs.a_pointh_3(), db.inputs.a_pointh_3());
        assign<array<carb::Double3>, const const_array<carb::Double3>>(db.outputs.a_pointd_3_array(), db.inputs.a_pointd_3_array());
        assign<array<carb::Float3>, const const_array<carb::Float3>>(db.outputs.a_pointf_3_array(), db.inputs.a_pointf_3_array());
        assign<array<pxr::GfVec3h>, const const_array<pxr::GfVec3h>>(db.outputs.a_pointh_3_array(), db.inputs.a_pointh_3_array());

        assign<carb::Double4, const carb::Double4>(db.outputs.a_quatd_4(), db.inputs.a_quatd_4());
        assign<carb::Float4, const carb::Float4>(db.outputs.a_quatf_4(), db.inputs.a_quatf_4());
        assign<pxr::GfQuath, const pxr::GfQuath>(db.outputs.a_quath_4(), db.inputs.a_quath_4());
        assign<array<carb::Double4>, const const_array<carb::Double4>>(db.outputs.a_quatd_4_array(), db.inputs.a_quatd_4_array());
        assign<array<carb::Float4>, const const_array<carb::Float4>>(db.outputs.a_quatf_4_array(), db.inputs.a_quatf_4_array());
        assign<array<pxr::GfQuath>, const const_array<pxr::GfQuath>>(db.outputs.a_quath_4_array(), db.inputs.a_quath_4_array());

        assign<string, const const_string>(db.outputs.a_string(), db.inputs.a_string());

        assign<carb::Double2, const carb::Double2>(db.outputs.a_texcoordd_2(), db.inputs.a_texcoordd_2());
        assign<carb::Double3, const carb::Double3>(db.outputs.a_texcoordd_3(), db.inputs.a_texcoordd_3());
        assign<carb::Float2, const carb::Float2>(db.outputs.a_texcoordf_2(), db.inputs.a_texcoordf_2());
        assign<carb::Float3, const carb::Float3>(db.outputs.a_texcoordf_3(), db.inputs.a_texcoordf_3());
        assign<pxr::GfVec2h, const pxr::GfVec2h>(db.outputs.a_texcoordh_2(), db.inputs.a_texcoordh_2());
        assign<pxr::GfVec3h, const pxr::GfVec3h>(db.outputs.a_texcoordh_3(), db.inputs.a_texcoordh_3());
        assign<array<carb::Double2>, const const_array<carb::Double2>>(db.outputs.a_texcoordd_2_array(), db.inputs.a_texcoordd_2_array());
        assign<array<carb::Double3>, const const_array<carb::Double3>>(db.outputs.a_texcoordd_3_array(), db.inputs.a_texcoordd_3_array());
        assign<array<carb::Float2>, const const_array<carb::Float2>>(db.outputs.a_texcoordf_2_array(), db.inputs.a_texcoordf_2_array());
        assign<array<carb::Float3>, const const_array<carb::Float3>>(db.outputs.a_texcoordf_3_array(), db.inputs.a_texcoordf_3_array());
        assign<array<pxr::GfVec2h>, const const_array<pxr::GfVec2h>>(db.outputs.a_texcoordh_2_array(), db.inputs.a_texcoordh_2_array());
        assign<array<pxr::GfVec3h>, const const_array<pxr::GfVec3h>>(db.outputs.a_texcoordh_3_array(), db.inputs.a_texcoordh_3_array());

        assign<pxr::SdfTimeCode, const pxr::SdfTimeCode>(db.outputs.a_timecode(), db.inputs.a_timecode());
        assign<array<pxr::SdfTimeCode>, const const_array<pxr::SdfTimeCode>>(db.outputs.a_timecode_array(), db.inputs.a_timecode_array());

        assign<NameToken, const NameToken>(db.outputs.a_token(), db.inputs.a_token());
        assign<array<NameToken>, const const_array<NameToken>>(db.outputs.a_token_array(), db.inputs.a_token_array());

        assign<uint8_t, const uint8_t>(db.outputs.a_uchar(), db.inputs.a_uchar());
        assign<array<uint8_t>, const const_array<uint8_t>>(db.outputs.a_uchar_array(), db.inputs.a_uchar_array());

        assign<uint32_t, const uint32_t>(db.outputs.a_uint(), db.inputs.a_uint());
        assign<array<uint32_t>, const const_array<uint32_t>>(db.outputs.a_uint_array(), db.inputs.a_uint_array());

        assign<uint64_t, const uint64_t>(db.outputs.a_uint64(), db.inputs.a_uint64());
        assign<array<uint64_t>, const const_array<uint64_t>>(db.outputs.a_uint64_array(), db.inputs.a_uint64_array());

        assign<carb::Double3, const carb::Double3>(db.outputs.a_vectord_3(), db.inputs.a_vectord_3());
        assign<carb::Float3, const carb::Float3>(db.outputs.a_vectorf_3(), db.inputs.a_vectorf_3());
        assign<pxr::GfVec3h, const pxr::GfVec3h>(db.outputs.a_vectorh_3(), db.inputs.a_vectorh_3());
        assign<array<carb::Double3>, const const_array<carb::Double3>>(db.outputs.a_vectord_3_array(), db.inputs.a_vectord_3_array());
        assign<array<carb::Float3>, const const_array<carb::Float3>>(db.outputs.a_vectorf_3_array(), db.inputs.a_vectorf_3_array());
        assign<array<pxr::GfVec3h>, const const_array<pxr::GfVec3h>>(db.outputs.a_vectorh_3_array(), db.inputs.a_vectorh_3_array());


        return true;
    }
};

REGISTER_OGN_NODE()

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