/******************************************************************************
 * Copyright 2019 NVIDIA Corporation. All rights reserved.
 *****************************************************************************/

#ifndef NVIDIA_INDEX_IPIPE_SET_SUBSET_H
#define NVIDIA_INDEX_IPIPE_SET_SUBSET_H

#include <nv/index/idistributed_data_subset.h>

namespace nv {
namespace index {

/// Helper for setting the parameters of a single pipe inside a subset. An instance of this
/// interface is returned by \c IPipe_set_subset::add_pipe().
class IPipe_subset_parameters :
    public mi::base::Interface_declare<0x3ee3429b,0x0607,0x4b87,0xb3,0xe6,0x9e,0x94,0x57,0x60,0x54,0x41>
{
public:
    /// Sets the radius of the pipe.
    ///
    /// \param[in] radius      Radius to be used for all vertices of the pipe.
    ///
    /// \return true on success, or false if the radius is 0 or negative.
    //
    virtual bool set_radius(mi::Float32 radius) = 0;

    /// Sets the color of a pipe. This is the base color only, which may be influenced by the
    /// assigned material during rendering, depending on the active rendering kernel program.
    ///
    /// \param[in] color       Base color to be used for all vertices of the pipe.
    ///
    virtual void set_color(const mi::math::Color_struct& color) = 0;

    /// Sets custom user flags of a pipe. The flags are passed through to rendering kernel programs
    /// and are not interpreted in any way by NVIDIA IndeX.
    ///
    /// \param[in] flags       Custom user flags.
    ///
    virtual void set_user_flags(mi::Uint32 flags) = 0;

    /// Sets the property that should be mapped onto the pipe. The property must already have been
    /// reserverved by \c reserve_property().
    ///
    /// \param[in] property_name  Unique name identifying the property, must already be reserved.
    ///
    /// \return true on success, or false if \c property_name is invalid or the property was not yet
    ///          reserved.
    //
    virtual bool set_property(const char* property_name) = 0;

    /// Sets the per-vertex coordinates for mapping property data onto the pipe.
    ///
    /// \param[in] property_coordinates     Array of 1D coordinates, or 0.
    /// \param[in] nb_property_coordinates  Number of coordinates in the array, must either be 0 or
    ///                                     match the number of vertices given to \c add_pipe().
    ///
    /// \return true on success, or false if one of the arguments is invalid.
    //
    virtual bool set_property_coordinates(
        const mi::Float32* property_coordinates,
        mi::Size           nb_property_coordinates) = 0;

    /// Specifies the domain-specific property coordinate values of the first and last vertex of the
    /// pipe. If this is not set, or when \c coordinate_first <= \c coordinate_last, then the entire
    /// coordinate range will be used.
    ///
    /// This should be used together with the corresponding parameters of \c
    /// IPipe_set_subset::set_property_data().
    ///
    /// \param[in] coordinate_first         Domain-specific property coordinate value of the first vertex.
    /// \param[in] coordinate_last          Domain-specific property coordinate value of the last vertex.
    ///
    /// \return true on success, or false if one of the arguments is invalid.
    //
    virtual void set_property_coordinates_range(
        mi::Float32 coordinate_first,
        mi::Float32 coordinate_last) = 0;

    /// Sets the expected value range of the property data for the pipe. The data values will be
    /// normalized (but not clipped/clamped) to [0 1], with \c value_min mapped to 0 and \c
    /// value_max mapped to 1.
    ///
    /// If \c value_min or \c value_max is set to +/-infinity then the actual min/max value found in
    /// the data will be used.
    ///
    /// \param[in] value_min  Data value that should be mapped to 0.
    /// \param[in] value_max  Data value that should be mapped to 1.
    ///
    /// \return true on success, or false if one of the arguments is invalid.
    //
    virtual void set_property_value_range(
        mi::Float32 value_min,
        mi::Float32 value_max) = 0;

    /// Sets information about the given pipe for the current subset/subregion. Since it is not
    /// possible to determine from the vertex data alone whether the overall start and end point of
    /// the entire subregion is contained in the current subset, providing this information allows
    /// for better optimization. However, it is also safe to always set \c true (which is the
    /// default).
    ///
    /// \param[in] contains_start_point  Pipe start point is contained in this subregion.
    /// \param[in] contains_end_point    Pipe end point is contained in this subregion.
    ///
    virtual void set_subset_status(
        mi::Float32 contains_start_point,
        mi::Float32 contains_end_point) = 0;
};

/// Distributed data storage for pipe sets.
class IPipe_set_subset :
    public mi::base::Interface_declare<0xea834969,0x1c60,0x4416,0xbd,0x05,0x3a,0x4b,0xbe,0x78,0xef,0x5f,
                                       IDistributed_data_subset>
{
public:
    /// Returns the bounding box of the subset.
    ///
    /// \return Bounding box in the local coordinate system.
    ///
    virtual const mi::math::Bbox_struct<mi::Float32, 3>& get_bounding_box() const = 0;

    /// Adds a new pipe with the given vertices.
    ///
    /// \param[in] vertices     Array of vertices
    /// \param[in] nb_vertices  Number of vertices in the array
    ///
    /// \return The new pipe that was just added to the subset. The caller takes ownership, but
    ///         should not store it longer than necessary. It must released before \c finalize() is
    ///         called.
    ///
    virtual IPipe_subset_parameters* add_pipe(
        const mi::math::Vector_struct<mi::Float32, 3>* vertices,
        mi::Size                                       nb_vertices) = 0;

    /// Returns whether data is available for the given property, or if it at least has been
    /// reserved.
    ///
    /// \param[in] property_name  Unique name identifying the property.
    ///
    /// \return true if property data is available or has been reserved.
    ///
    virtual bool has_property(const char* property_name) const = 0;

    /// Tries to reserve the given property to the caller, so that it can start loading the property
    /// data. This approach is necessary to ensure property data won't get loaded by multiple
    /// concurrent threads.
    ///
    /// \param[in] property_name  Unique name identifying the property.
    ///
    /// \return true if reservation succeeded, or false if the property was already reserved.
    ///
    virtual bool reserve_property(const char* property_name) const = 0;

    /// Stores the data for the given property. To prevent interference between multiple threads,
    /// this should only get called by the thread for which \c reserve_property() returned true.
    ///
    /// Optionally, the property coordinates for the first and last property value may be specified.
    /// This should be used together with \c IPipe_subset_parameters::set_property_coordinates_range().
    ///
    /// \param[in] property_name       Unique name identifying the property.
    /// \param[in] property_values     Array of property values.
    /// \param[in] nb_property_values  Number of values in the array.
    /// \param[in] coordinate_first    Coordinate of the first property value.
    /// \param[in] coordinate_last     Coordinate of the last property value.
    ///
    /// \return true on success, or false if one of the arguments is invalid.
    ///
    virtual bool set_property_data(
        const char*        property_name,
        const mi::Float32* property_values,
        mi::Size           nb_property_values,
        mi::Float32        coordinate_first = 0.f,
        mi::Float32        coordinate_last = 0.f) = 0;
};

}} // namespace

#endif // NVIDIA_INDEX_ICORNER_POINT_GRID_SUBSET_H
