/*
 * Copyright (C) 2015 Open Source Robotics Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#ifndef GZ_RENDERING_VISUAL_HH_
#define GZ_RENDERING_VISUAL_HH_

#include <variant>
#include <string>
#include "gz/rendering/config.hh"
#include "gz/rendering/Node.hh"

namespace ignition
{
  namespace rendering
  {
    inline namespace IGNITION_RENDERING_VERSION_NAMESPACE {
    //
    using Variant = std::variant<int, float, double, std::string>;

    /// \class Visual Visual.hh ignition/rendering/Visual.hh
    /// \brief Represents a visual node in a scene graph. A Visual is the only
    /// node that can have Geometry and other Visual children.
    class IGNITION_RENDERING_VISIBLE Visual :
      public virtual Node
    {
      /// \brief Deconstructor
      public: virtual ~Visual() { }

      /// \brief Get the number of geometries attached to this visual
      /// \return The number of geometries attached to this visual
      public: virtual unsigned int GeometryCount() const = 0;

      /// \brief Determine if given geometry is attached to this visual
      /// \param[in] _geometry Geometry in question
      /// \return True if given node is attached to this visual
      public: virtual bool HasGeometry(ConstGeometryPtr _geometry) const = 0;

      /// \brief Get geometry at given index. If no geometry exists at given
      /// index, NULL will be returned.
      /// \param[in] _index Index of the desired geometry
      /// \return The specified geometry
      public: virtual GeometryPtr GeometryByIndex(
                  unsigned int _index) const = 0;

      /// \brief Add the given geometry to this visual. If the given node is
      /// already attached, no work will be done.
      /// \param[in] _geometry Geometry to be added
      public: virtual void AddGeometry(GeometryPtr _geometry) = 0;

      /// \brief Remove the given geometry from this visual. If the given node
      /// is not a child of this visual, no work will be done.
      /// \param[in] _geometry Geometry to be removed
      /// \return The removed geometry
      public: virtual GeometryPtr RemoveGeometry(GeometryPtr _geometry) = 0;

      /// \brief Remove the geometry at the given index from this visual. If the
      /// specified node is not attached this visual, no work will be done.
      /// \param[in] _index Index of the geometry to be removed
      /// \return The removed geometry
      public: virtual GeometryPtr RemoveGeometryByIndex(
                  unsigned int _index) = 0;

      /// \brief Remove all attached geometries from this visual
      public: virtual void RemoveGeometries() = 0;

      /// \brief Set the material for all attached visuals and geometries. The
      /// specified material will be retrieved from Scene::Material using
      /// the given material name. If no material is registered with the given
      /// name, no work will be done.
      /// \param[in] _name Name of the material to be assigned
      /// \param[in] _unique True if the specified material should be cloned
      public: virtual void SetMaterial(const std::string &_name,
                  bool _unique = true) = 0;

      /// \brief Set the material for all attached visuals and geometries
      /// \param[in] _material Name of the material to be assigned
      /// \param[in] _unique True if the specified material should be cloned
      public: virtual void SetMaterial(MaterialPtr _material,
                  bool _unique = true) = 0;

      /// \brief Set the material for all attached visuals only
      /// \param[in] _material Name of the material to be assigned
      /// \param[in] _unique True if the specified material should be cloned
      public: virtual void SetChildMaterial(MaterialPtr _material,
                  bool _unique = true) = 0;

      /// \brief Set the material for all attached geometries only
      /// \param[in] _material Name of the material to be assigned
      /// \param[in] _unique True if the specified material should be cloned
      public: virtual void SetGeometryMaterial(MaterialPtr _material,
                  bool _unique = true) = 0;

      /// \brief Get the material assigned to attached visuals and geometries.
      /// \return the Pointer to the material assigned to this visual. If the
      /// material is cloned at the time it is set to this visual, the cloned
      /// material will be returned.
      public: virtual MaterialPtr Material() = 0;

      /// \brief Specify if this visual is visible
      /// \param[in] _visible True if this visual should be made visible
      public: virtual void SetVisible(bool _visible) = 0;

      /// \brief Store any custom data associated with this visual
      /// \param[in] _key Unique key
      /// \param[in] _value Value in any type
      public: virtual void SetUserData(const std::string &_key,
          Variant _value) = 0;

      /// \brief Get custom data stored in this visual
      /// \param[in] _key Unique key
      /// \return Data associated with the key.
      public: virtual Variant UserData(const std::string &_key) const = 0;
    };
    }
  }
}
#endif
