/*
 * Copyright (C) 2012 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 GAZEBO_PHYSICS_LINK_HH_
#define GAZEBO_PHYSICS_LINK_HH_

#include <map>
#include <vector>
#include <string>
#include <ignition/math/Matrix3.hh>

#include "gazebo/msgs/msgs.hh"

#include "gazebo/common/Event.hh"
#include "gazebo/common/CommonTypes.hh"

#include "gazebo/physics/LinkState.hh"
#include "gazebo/physics/Entity.hh"
#include "gazebo/physics/Inertial.hh"
#include "gazebo/physics/Joint.hh"
#include "gazebo/util/system.hh"

namespace gazebo
{
  namespace physics
  {
    class Model;
    class Collision;
    class Battery;
    class LinkPrivate;

    /// \addtogroup gazebo_physics
    /// \{

    /// \class Link Link.hh physics/physics.hh
    /// \brief Link class defines a rigid body entity, containing
    /// information on inertia, visual and collision properties of
    /// a rigid body.
    class GZ_PHYSICS_VISIBLE Link : public Entity
    {
      /// \brief Constructor
      /// \param[in] _parent Parent of this link.
      public: explicit Link(EntityPtr _parent);

      /// \brief Destructor.
      public: virtual ~Link();

      /// \brief Load the body based on an SDF element.
      /// \param[in] _sdf SDF parameters.
      public: virtual void Load(sdf::ElementPtr _sdf) override;

      /// \brief Initialize the body.
      public: virtual void Init() override;

      /// \brief Finalize the body.
      public: void Fini() override;

      /// \brief Reset the link.
      public: void Reset() override;
      using Entity::Reset;

      /// \brief Reset the velocity, acceleration, force and torque of link.
      public: void ResetPhysicsStates();

      /// \brief Update the parameters using new sdf values.
      /// \param[in] _sdf SDF values to load from.
      public: virtual void UpdateParameters(sdf::ElementPtr _sdf) override;

      /// \brief Update the collision.
      /// \param[in] _info Update information.
      public: void Update(const common::UpdateInfo &_info);
      using Base::Update;

      /// \brief Set the scale of the link.
      /// \param[in] _scale Scale to set the link to.
      public: void SetScale(const ignition::math::Vector3d &_scale);

      /// \brief Set whether this body is enabled.
      /// \param[in] _enable True to enable the link in the physics engine.
      public: virtual void SetEnabled(bool _enable) const = 0;

      /// \brief Get whether this body is enabled in the physics engine.
      /// \return True if the link is enabled.
      public: virtual bool GetEnabled() const = 0;

      /// \brief Set whether this entity has been selected by the user
      /// through the gui
      /// \param[in] _set True to set the link as selected.
      public: virtual bool SetSelected(bool _set) override;

      /// \brief Set whether gravity affects this body.
      /// \param[in] _mode True to enable gravity.
      public: virtual void SetGravityMode(bool _mode) = 0;

      /// \brief Get the gravity mode.
      /// \return True if gravity is enabled.
      public: virtual bool GetGravityMode() const = 0;

      /// \brief Set whether wind affects this body.
      /// \param[in] _mode True to enable wind.
      public: virtual void SetWindMode(const bool _mode);

      /// \brief Get the wind mode.
      /// \return True if wind is enabled.
      public: virtual bool WindMode() const;

      /// \brief Set whether this body will collide with others in the
      /// model.
      /// \sa GetSelfCollide
      /// \param[in] _collide True to enable collisions.
      public: virtual void SetSelfCollide(bool _collide) = 0;

      /// \brief Set the collide mode of the body.
      /// \param[in] _mode Collision Mode,
      /// this can be: [all|none|sensors|fixed|ghost]
      /// all: collides with everything
      /// none: collides with nothing
      /// sensors: collides with everything else but other sensors
      /// fixed: collides with everything else but other fixed
      /// ghost: collides with everything else but other ghost
      public: void SetCollideMode(const std::string &_mode);

      /// \brief Get Self-Collision Flag.
      /// Two links within the same model will not collide if both have
      /// self_collide == false. \n
      /// link 1 and link2 collide = link1.self_collide || link2.self_collide
      /// Bodies connected by a joint are exempt from this, and will
      /// never collide.
      /// \return True if self collision is enabled.
      public: bool GetSelfCollide() const;

      /// \brief Set the laser retro reflectiveness.
      /// \param[in] _retro Retro value for all child collisions.
      public: void SetLaserRetro(float _retro);

      /// \brief Set the linear velocity of the body.
      /// \param[in] _vel Linear velocity.
      public: virtual void SetLinearVel(
                  const ignition::math::Vector3d &_vel) = 0;

      /// \brief Set the angular velocity of the body.
      /// \param[in] _vel Angular velocity.
      public: virtual void SetAngularVel(
                  const ignition::math::Vector3d &_vel) = 0;

      /// \brief Set the force applied to the body.
      /// \param[in] _force Force value.
      public: virtual void SetForce(
                  const ignition::math::Vector3d &_force) = 0;

      /// \brief Set the torque applied to the body.
      /// \param[in] _torque Torque value.
      public: virtual void SetTorque(
                  const ignition::math::Vector3d &_torque) = 0;

      /// \brief Add a force to the body.
      /// \param[in] _force Force to add.
      public: virtual void AddForce(const ignition::math::Vector3d &_force) = 0;

      /// \brief Add a force to the body, components are relative to the
      /// body's own frame of reference.
      /// \param[in] _force Force to add.
      public: virtual void AddRelativeForce(
                  const ignition::math::Vector3d &_force) = 0;

      /// \brief Add a force to the body using a global position.
      /// \param[in] _force Force to add.
      /// \param[in] _pos Position in global coord frame to add the force.
      public: virtual void AddForceAtWorldPosition(
                  const ignition::math::Vector3d &_force,
                  const ignition::math::Vector3d &_pos) = 0;

      /// \brief Add a force (in world frame coordinates) to the body at a
      /// position relative to the center of mass which is expressed in the
      /// link's own frame of reference.
      /// \param[in] _force Force to add. The force must be expressed in the
      /// world reference frame.
      /// \param[in] _relPos Position on the link to add the force. This
      /// position must be expressed in the link's coordinates with respect to
      /// the link's center of mass.
      public: virtual void AddForceAtRelativePosition(
                  const ignition::math::Vector3d &_force,
                  const ignition::math::Vector3d &_relPos) = 0;

      /// \brief Add a force expressed in the link frame.
      /// \param[in] _force Force to add. The force must be expressed in the
      /// link-fixed reference frame.
      /// \param[in] _offset Offset position expressed in coordinates of the
      /// link frame with respect to the link frame's origin. It defaults to the
      /// link origin.
      public: virtual void AddLinkForce(
                  const ignition::math::Vector3d &_force,
                  const ignition::math::Vector3d &_offset =
                      ignition::math::Vector3d::Zero) = 0;

      /// \brief Add a torque to the body.
      /// \param[in] _torque Torque value to add to the link.
      public: virtual void AddTorque(
                  const ignition::math::Vector3d &_torque) = 0;

      /// \brief Add a torque to the body, components are relative to the
      /// body's own frame of reference.
      /// \param[in] _torque Torque value to add.
      public: virtual void AddRelativeTorque(
                  const ignition::math::Vector3d &_torque) = 0;

      /// \brief Get the pose of the body's center of gravity in the world
      ///        coordinate frame.
      /// \return Pose of the body's center of gravity in the world coordinate
      ///         frame.
      public: ignition::math::Pose3d WorldCoGPose() const;

      /// \brief Get the linear velocity of the origin of the link frame,
      ///        expressed in the world frame.
      /// \return Linear velocity of the link frame.
      public: virtual ignition::math::Vector3d WorldLinearVel() const override;

      /// \brief Get the linear velocity of a point on the body in the world
      ///        frame, using an offset expressed in a body-fixed frame. If
      ///        no offset is given, the velocity at the origin of the Link
      ///        frame will be returned.
      /// \param[in] _offset Offset of the point from the origin of the Link
      ///                    frame, expressed in the body-fixed frame.
      /// \return Linear velocity of the point on the body
      public: virtual ignition::math::Vector3d WorldLinearVel(
                  const ignition::math::Vector3d &_offset) const = 0;

      /// \brief Get the linear velocity of a point on the body in the world
      ///        frame, using an offset expressed in an arbitrary frame.
      /// \param[in] _offset Offset from the origin of the link frame expressed
      ///                    in a frame defined by _q.
      /// \param[in] _q Describes the rotation of a reference frame relative to
      ///               the world reference frame.
      /// \return Linear velocity of the point on the body in the world frame.
      public: virtual ignition::math::Vector3d WorldLinearVel(
                  const ignition::math::Vector3d &_offset,
                  const ignition::math::Quaterniond &_q) const = 0;

      /// \brief Get the linear velocity at the body's center of gravity in the
      ///        world frame.
      /// \return Linear velocity at the body's center of gravity in the world
      ///         frame.
      public: virtual ignition::math::Vector3d WorldCoGLinearVel() const = 0;

      /// \brief Get the linear velocity of the body.
      /// \return Linear velocity of the body.
      public: ignition::math::Vector3d RelativeLinearVel() const override;

      /// \brief Get the angular velocity of the body.
      /// \return Angular velocity of the body.
      public: ignition::math::Vector3d RelativeAngularVel() const override;

      /// \brief Get the linear acceleration of the body.
      /// \return Linear acceleration of the body.
      public: ignition::math::Vector3d RelativeLinearAccel() const override;

      /// \brief Get the linear acceleration of the body in the world frame.
      /// \return Linear acceleration of the body in the world frame.
      public: ignition::math::Vector3d WorldLinearAccel() const override;

      /// \brief Get the angular acceleration of the body.
      /// \return Angular acceleration of the body.
      public: ignition::math::Vector3d RelativeAngularAccel() const override;

      /// \brief Get the angular momentum of the body CoG in the world frame,
      /// which is computed as (I * w), where
      /// I: inertia matrix in world frame
      /// w: angular velocity in world frame
      /// \return Angular momentum of the body.
      public: ignition::math::Vector3d WorldAngularMomentum() const;

      /// \brief Get the angular acceleration of the body in the world frame,
      /// which is computed as (I^-1 * (T - w x L)), where
      /// I: inertia matrix in world frame
      /// T: sum of external torques in world frame
      /// L: angular momentum of CoG in world frame
      /// w: angular velocity in world frame
      /// \return Angular acceleration of the body in the world frame.
      public: ignition::math::Vector3d WorldAngularAccel() const override;

      /// \brief Get the force applied to the body.
      /// \return Force applied to the body.
      public: ignition::math::Vector3d RelativeForce() const;

      /// \brief Get the force applied to the body in the world frame.
      /// \return Force applied to the body in the world frame.
      public: virtual ignition::math::Vector3d WorldForce() const = 0;

      /// \brief Get the torque applied to the body.
      /// \return Torque applied to the body.
      public: ignition::math::Vector3d RelativeTorque() const;

      /// \brief Get the torque applied to the body about the center of mass in
      /// world frame coordinates.
      /// \return Torque applied to the body in the world frame.
      public: virtual ignition::math::Vector3d WorldTorque() const = 0;

      /// \brief Get the model that this body belongs to.
      /// \return Model that this body belongs to.
      public: ModelPtr GetModel() const;

      /// \brief Get the inertia of the link.
      /// \return Inertia of the link.
      public: InertialPtr GetInertial() const {return this->inertial;}

      /// \brief Set the mass of the link.
      /// \parma[in] _inertial Inertial value for the link.
      public: void SetInertial(const InertialPtr &_inertial);

      /// \brief Get the world pose of the link inertia (cog position
      /// and Moment of Inertia frame). This differs from GetWorldCoGPose(),
      /// which returns the cog position in the link frame
      /// (not the Moment of Inertia frame).
      /// \return Inertial pose in world frame.
      public: ignition::math::Pose3d WorldInertialPose() const;

      /// \brief Get the inertia matrix in the world frame.
      /// \return Inertia matrix in world frame, returns matrix
      /// of zeros if link has no inertia.
      public: ignition::math::Matrix3d WorldInertiaMatrix() const;

      /// \cond
      /// This is an internal function
      /// \brief Get a collision by id.
      /// \param[in] _id Id of the collision object to find.
      /// \return Pointer to the collision, NULL if the id is invalid.
      public: CollisionPtr GetCollisionById(unsigned int _id) const;
      /// \endcond

      /// \brief Get a child collision by name
      /// \param[in] _name Name of the collision object.
      /// \return Pointer to the collision, NULL if the name was not found.
      public: CollisionPtr GetCollision(const std::string &_name);

      /// \brief Get a child collision by index
      /// \param[in] _index Index of the collision object.
      /// \return Pointer to the collision, NULL if the name was not found.
      public: CollisionPtr GetCollision(unsigned int _index) const;

      /// \brief Get all the child collisions.
      /// \return A std::vector of all the child collisions.
      public: Collision_V GetCollisions() const;

      /// \brief Get the bounding box for the link and all the child
      /// elements.
      /// \return The link's bounding box.
      public: virtual ignition::math::AxisAlignedBox BoundingBox() const
          override;

      /// \brief Set the linear damping factor.
      /// \param[in] _damping Linear damping factor.
      public: virtual void SetLinearDamping(double _damping) = 0;

      /// \brief Set the angular damping factor.
      /// \param[in] _damping Angular damping factor.
      public: virtual void SetAngularDamping(double _damping) = 0;

      /// \brief Get the linear damping factor.
      /// \return Linear damping.
      public: double GetLinearDamping() const;

      /// \brief Get the angular damping factor.
      /// \return Angular damping.
      public: double GetAngularDamping() const;

      /// \TODO Implement this function.
      /// \brief Set whether this body is in the kinematic state.
      /// \param[in] _kinematic True to make the link kinematic only.
      public: virtual void SetKinematic(const bool &_kinematic);

      /// \TODO Implement this function.
      /// \brief Get whether this body is in the kinematic state.
      /// \return True if the link is kinematic only.
      public: virtual bool GetKinematic() const {return false;}

      /// \brief Get sensor count
      ///
      /// This will return the number of sensors created by the link when it
      /// was loaded. This function is commonly used with
      /// Link::GetSensorName.
      /// \return The number of sensors created by the link.
      public: unsigned int GetSensorCount() const;

      /// \brief Get sensor name
      ///
      /// Get the name of a sensor based on an index. The index should be in
      /// the range of 0...Link::GetSensorCount().
      /// \note A Link does not manage or maintain a pointer to a
      /// sensors::Sensor. Access to a Sensor object
      /// is accomplished through the sensors::SensorManager. This was done to
      /// separate the physics engine from the sensor engine.
      /// \param[in] _index Index of the sensor name.
      /// \return The name of the sensor, or empty string if the index is out of
      /// bounds.
      public: std::string GetSensorName(unsigned int _index) const;

      /// \brief Connect to the add entity signal
      /// \param[in] _subscriber Subsciber callback function.
      /// \return Pointer to the connection, which must be kept in scope.
      public: event::ConnectionPtr ConnectEnabled(
          std::function<void (bool)> _subscriber);

      /// \brief Fill a link message
      /// \param[out] _msg Message to fill
      public: void FillMsg(msgs::Link &_msg);

      /// \brief Update parameters from a message
      /// \param[in] _msg Message to read.
      public: void ProcessMsg(const msgs::Link &_msg);

      /// \brief Joints that have this Link as a parent Link.
      /// \param[in] _joint Joint that is a child of this link.
      public: void AddChildJoint(JointPtr _joint);

      /// \brief Joints that have this Link as a child Link.
      /// \param[in] _joint Joint that is a parent of this link.
      public: void AddParentJoint(JointPtr _joint);

      /// \brief Remove Joints that have this Link as a child Link.
      /// \param[in] _jointName Parent Joint name.
      public: void RemoveParentJoint(const std::string &_jointName);

      /// \brief Remove Joints that have this Link as a parent Link
      /// \param[in] _jointName Child Joint name.
      public: void RemoveChildJoint(const std::string &_jointName);

      // Documentation inherited.
      public: virtual void RemoveChild(EntityPtr _child);
      using Base::RemoveChild;

      /// \brief Attach a static model to this link
      /// \param[in] _model Pointer to a static model.
      /// \param[in] _offset Pose relative to this link to place the model.
      public: void AttachStaticModel(ModelPtr &_model,
                                     const ignition::math::Pose3d &_offset);

      /// \brief Detach a static model from this link.
      /// \param[in] _modelName Name of an attached model to detach.
      public: void DetachStaticModel(const std::string &_modelName);

      /// \brief Detach all static models from this link.
      public: void DetachAllStaticModels();

      /// \internal
      /// \brief Called when the pose is changed. Do not call this directly.
      public: virtual void OnPoseChange() override;

      /// \brief Set the current link state.
      /// \param[in] _state The state to set the link to.
      public: void SetState(const LinkState &_state);

      /// \brief Update the mass matrix.
      public: virtual void UpdateMass() {}

      /// \brief Update surface parameters.
      public: virtual void UpdateSurface() {}

      /// \brief Allow the link to auto disable.
      /// \param[in] _disable If true, the link is allowed to auto disable.
      public: virtual void SetAutoDisable(bool _disable) = 0;

      /// \brief Returns a vector of children Links connected by joints.
      /// \return A vector of children Links connected by joints.
      public: Link_V GetChildJointsLinks() const;

      /// \brief Returns a vector of parent Links connected by joints.
      /// \return Vector of parent Links connected by joints.
      public: Link_V GetParentJointsLinks() const;

      /// \brief Enable/Disable link data publishing
      /// \param[in] _enable True to enable publishing, false to stop publishing
      public: void SetPublishData(bool _enable);

      /// \brief Get the parent joints.
      public: Joint_V GetParentJoints() const;

      /// \brief Get the child joints.
      public: Joint_V GetChildJoints() const;

      /// \brief Remove a collision from the link.
      /// \param[int] _name Name of the collision to remove.
      public: void RemoveCollision(const std::string &_name);

      /// \brief Returns this link's potential energy,
      /// based on position in world frame and gravity.
      /// \return this link's potential energy,
      public: double GetWorldEnergyPotential() const;

      /// \brief Returns this link's kinetic energy
      /// computed using link's CoG velocity in the inertial (world) frame.
      /// \return this link's kinetic energy
      public: double GetWorldEnergyKinetic() const;

      /// \brief Returns this link's total energy, or
      /// sum of Link::GetWorldEnergyPotential() and
      /// Link::GetWorldEnergyKinetic().
      /// \return this link's total energy
      public: double GetWorldEnergy() const;

      /// \brief Returns the visual message specified by its name
      /// \param[in] name of the visual message
      /// \return visual message
      public: msgs::Visual GetVisualMessage(const std::string &_name) const;

      /// \brief Freeze link to ground (inertial frame).
      /// \param[in] _static if true, freeze link to ground.  Otherwise
      /// unfreeze link.
      public: virtual void SetLinkStatic(bool _static) = 0;

      // Documentation inherited
      public: virtual void SetStatic(const bool &_static);
      using Entity::SetStatic;

      /// \brief Move Link given source and target frames specified in
      /// world coordinates. Assuming link's relative pose to
      /// source frame (_worldReferenceFrameSrc) remains unchanged relative
      /// to destination frame (_worldReferenceFrameDst).
      /// \param[in] _worldReferenceFrameSrc initial reference frame to
      /// which this link is attached.
      /// \param[in] _worldReferenceFrameDst final location of the
      /// reference frame specified in world coordinates.
      /// \param[in] _preserveWorldVelocity True if to preserve the world
      /// velocity before move frame, default is false.
      public: void MoveFrame(
                  const ignition::math::Pose3d &_worldReferenceFrameSrc,
                  const ignition::math::Pose3d &_worldReferenceFrameDst,
                  const bool _preserveWorldVelocity = false);

      /// \brief Helper function to find all connected links of a link
      /// based on parent/child relations of joints. For example,
      /// if Link0 --> Link1 --> ... --> LinkN is a kinematic chain
      /// with Link0 being the base link.  Then, call by Link1:
      ///   Link1->FindAllConnectedLinksHelper(Link0, _list, true);
      /// should return true with _list containing Link1 through LinkN.
      /// In the case the _originalParentLink is part of a loop,
      /// _connectedLinks is cleared and the function returns false.
      /// \param[in] _originParentLink if this link is a child link of
      /// the search, we've found a loop.
      /// \param[in/out] _connectedLinks aggregate list of connected links.
      /// \param[in] _fistLink this is the first Link, skip over the parent
      /// link that matches the _originalParentLink.
      /// \return true if successfully found a subset of connected links
      public: bool FindAllConnectedLinksHelper(
        const LinkPtr &_originalParentLink,
        Link_V &_connectedLinks, bool _fistLink = false);

      /// \brief Enable/disable wind for this link.
      /// \param[in] _enable True to enable the wind.
      public: void SetWindEnabled(const bool _enable);

      /// \brief Returns this link's wind velocity in the world coordinate
      /// frame.
      /// \return this link's wind velocity.
      public: const ignition::math::Vector3d WorldWindLinearVel() const;

      /// \brief Returns this link's wind velocity.
      /// \return this link's wind velocity.
      public: const ignition::math::Vector3d RelativeWindLinearVel() const;

      /// \brief Update the wind.
      /// \param[in] _info Update information.
      public: void UpdateWind(const common::UpdateInfo &_info);

      /// \brief Get a battery by name.
      /// \param[in] _name Name of the battery to get.
      /// \return Pointer to the battery, NULL if the name is invalid.
      public: common::BatteryPtr Battery(const std::string &_name) const;

      /// \brief Get a battery based on an index.
      /// \return A pointer to a Battery. Null if the _index is invalid.
      public: common::BatteryPtr Battery(const size_t _index) const;

      /// \brief Get the number of batteries in this link.
      /// \return Size of this->batteries array.
      /// \sa Link::Battery()
      public: size_t BatteryCount() const;

      /// \brief Get the unique ID of a visual.
      /// \param[in] _visName Name of the visual.
      /// \param[out] _visualId The unique ID of the visual.
      /// \return True if getting the unique ID of the visual was successful.
      public: bool VisualId(const std::string &_visName, uint32_t &_visualId)
        const;

      /// \brief Get the pose of a visual.
      /// \param[in] _id Unique ID of visual.
      /// \param[out] _pose Pose of the visual relative to this link.
      /// \return True if getting the pose of the visual was successful.
      public: bool VisualPose(const uint32_t _id,
                  ignition::math::Pose3d &_pose) const;

      /// \brief Set the pose of a visual.
      /// \param[in] _id Unique ID of visual message.
      /// \param[in] _pose Pose relative to this link to place the visual.
      /// \return True if setting the pose of the visual was successful.
      public: bool SetVisualPose(const uint32_t _id,
                                 const ignition::math::Pose3d &_pose);

      /// \brief Get the SDF DOM object of this link
      /// \return Pointer to SDF DOM Object
      public: const sdf::Link *GetSDFDom() const;

      // Documentation inherited.
      public: std::optional<sdf::SemanticPose> SDFSemanticPose() const override;

      /// \def Visuals_M
      /// \brief Map of unique ID to visual message.
      typedef std::map<uint32_t, msgs::Visual> Visuals_M;

      /// \brief Return the link visual elements.
      /// \return a map of unique ID to visual message
      public: const Visuals_M &Visuals() const;

      /// \brief Publish timestamped link data such as velocity.
      private: void PublishData();

      /// \brief Load a new collision helper function.
      /// \param[in] _sdf SDF element used to load the collision.
      private: void LoadCollision(sdf::ElementPtr _sdf);

      /// \brief Load a light.
      /// \param[in] _sdf SDF element
      private: void LoadLight(sdf::ElementPtr _sdf);

      /// \brief Set the inertial properties based on the collision
      /// entities.
      private: void SetInertialFromCollisions();

      /// \brief On collision callback.
      /// \param[in] _msg Message that contains contact information.
      private: void OnCollision(ConstContactsPtr &_msg);

      /// \brief Parse visuals from SDF
      private: void ParseVisuals();

      /// \brief Helper function to see if _value is contained in _vector.
      /// \param[in] _vector a vector of boost link pointers.
      /// \param[in] _value a particular link pointer.
      /// \return true if value is in vector.
      private: bool ContainsLink(const Link_V &_vector, const LinkPtr &_value);

      /// \brief Update visual SDF's geometry size with the new scale.
      /// \param[in] _scale New scale applied to the visual
      private: void UpdateVisualGeomSDF(const ignition::math::Vector3d &_scale);

      /// \brief Update visual msgs.
      private: void UpdateVisualMsg();

      /// \brief Called when a new wrench message arrives. The wrench's force,
      /// torque and force offset are described in the link frame,
      /// \param[in] _msg The wrench message.
      private: void OnWrenchMsg(ConstWrenchPtr &_msg);

      /// \brief Process the message and add force and torque.
      /// \param[in] _msg The message to set the wrench from.
      private: void ProcessWrenchMsg(const msgs::Wrench &_msg);

      /// \brief Load a battery.
      /// \param[in] _sdf SDF parameter.
      private: void LoadBattery(const sdf::ElementPtr _sdf);

      /// \brief Register items in the introspection service.
      protected: virtual void RegisterIntrospectionItems() override;

      /// \brief Inertial properties.
      protected: InertialPtr inertial;

      /// \brief Link visual elements.
      protected: Visuals_M visuals;

      /// \brief Offsets for the attached models.
      protected: std::vector<ignition::math::Pose3d> attachedModelsOffset;

      /// \brief This flag is set to true when the link is initialized.
      protected: bool initialized = false;

      /// \brief Pointer to private data
      private: std::unique_ptr<LinkPrivate> dataPtr;
    };
    /// \}
  }
}
#endif
