/*
 * Copyright (C) 2018 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_FUEL_TOOLS_WORLDIDENTIFIER_HH_
#define GZ_FUEL_TOOLS_WORLDIDENTIFIER_HH_

#include <memory>
#include <string>

#include "gz/fuel_tools/Helpers.hh"

#ifdef _WIN32
// Disable warning C4251 which is triggered by
// std::unique_ptr
#pragma warning(push)
#pragma warning(disable: 4251)
#endif

namespace ignition
{
  namespace fuel_tools
  {
    /// \brief Forward Declaration
    class WorldIdentifierPrivate;
    class ServerConfig;

    /// \brief Defines how to identify a world
    class IGNITION_FUEL_TOOLS_VISIBLE WorldIdentifier
    {
      /// \brief Constructor.
      public: WorldIdentifier();

      /// \brief Copy Constructor.
      /// \param[in] _orig WorldIdentifier to copy.
      public: WorldIdentifier(const WorldIdentifier &_orig);

      /// \brief Destructor.
      public: ~WorldIdentifier();

      /// \brief Assignment operator
      /// \param[in] _orig WorldIdentifier to copy.
      /// \return Reference to this object.
      public: WorldIdentifier &operator=(const WorldIdentifier &_orig);

      /// \brief Equality operator.
      /// \param[in] _rhs WorldIdentifier to compare.
      /// \return True if the WorldIdentifier names are equal.
      public: bool operator==(const WorldIdentifier &_rhs) const;

      /// \brief Returns the world name
      /// \return World name.
      public: std::string Name() const;

      /// \brief Set the name of the world.
      /// \param[in] _name The name to set.
      /// \return True if successful.
      public: bool SetName(const std::string &_name);

      /// \brief Returns owner to attribute world to.
      /// \return Owner name.
      public: std::string Owner() const;

      /// \brief Set the owner of the world
      /// \param[in] _name The name to set. Must be ascii and pass [-_a-z0-9]+
      /// \return true if successful
      public: bool SetOwner(const std::string &_name);

      /// \brief Returns server information to retrieve world from.
      /// \return Server information.
      public: ServerConfig &Server() const;

      /// \brief Set the server from which this world comes.
      /// \param[in] _server The server to retrieve the world from.
      /// \return True if successful.
      public: bool SetServer(const ServerConfig &_server);

      /// \brief Returns the world's version as a number. Versions are integers
      /// counting from 1. Version zero means the tip.
      /// \return World's version.
      /// \sa VersionStr
      /// \sa SetVersion
      public: unsigned int Version() const;

      /// \brief Returns the world's version as a string. Versions are integers
      /// counting from 1. The strings "tip" or "" mean the latest version.
      /// \return World's version.
      /// \sa Version
      /// \sa SetVersionStr
      public: std::string VersionStr() const;

      /// \brief Set the world's version. Versions are integers counting from
      /// 1.
      /// \param[in] _version The world's version
      /// \return True if successful.
      /// \sa Version
      /// \sa SetVersionStr
      public: bool SetVersion(const unsigned int _version);

      /// \brief Set the world's version. Versions are integers counting from
      /// 1 or "tip" for the latest version.
      /// \param[in] _version The world's version
      /// \return True if successful.
      /// \sa VersionStr
      /// \sa SetVersion
      public: bool SetVersionStr(const std::string &_version);

      /// \brief Returns a path to the world on disk if it is already cached
      /// \returns Path, or empty string if the path has not been set
      /// \sa SetLocalPath
      public: std::string LocalPath() const;

      /// \brief Sets the path of the world in the local cache.
      /// \param[in] Local path to world.
      /// \sa LocalPath
      public: bool SetLocalPath(const std::string &_path);

      /// \brief Returns a unique name for the world.
      /// \remarks this is Server/Owner/Name.
      /// \return Unique world name.
      public: std::string UniqueName() const;

      // /// \brief Sets the SHA 2 256 hash of the world
      // /// \param[in] _hash a 256 bit SHA 2 hash
      // /// \returns true if successful
      // public: bool SHA_256(const std::array<std::uint8_t, 32> &_hash);

      /// \brief Returns all the world information as a string. Convenient for
      /// debugging.
      /// \param[in] _prefix Optional prefix for every line of the string.
      /// \return World information string
      public: std::string AsString(const std::string &_prefix = "") const;

      /// \brief Returns all the available world information as a string using
      /// colors for better human parsing.
      /// \param[in] _prefix Optional prefix for every line of the string.
      /// \return World information string
      public: std::string AsPrettyString(const std::string &_prefix = "") const;

      /// \brief PIMPL
      private: std::unique_ptr<WorldIdentifierPrivate> dataPtr;
    };
  }
}

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#endif
