/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
#ifndef itksys_Status_hxx
#define itksys_Status_hxx

#include <itksys/Configure.hxx>

#include <string>

/*
 * Detect a symbol collision with the name of this class. X11 headers use
 * `#define Status int` instead of using `typedef` which poisons any other
 * usage of this name.
 */
#if defined(Status) && defined(_X11_XLIB_H_)
#  error                                                                      \
    "Status.hxx must be included *before* any X11 headers to avoid a collision with the `Status` define that is made in its API."
#endif

namespace itksys {

/** \class Status
 * \brief OS-specific status of a system operation.
 */
class itksys_EXPORT Status
{
public:
  enum class Kind
  {
    Success,
    POSIX,
#ifdef _WIN32
    Windows,
#endif
  };

  /** Construct with kind "Success".  */
  Status() = default;

  /** Construct with kind "Success".  */
  static Status Success() { return Status(); }

  /** Construct with kind "POSIX" using given errno-style value.  */
  static Status POSIX(int e)
  {
    Status s(Kind::POSIX);
    s.POSIX_ = e;
    return s;
  }

  /** Construct with kind "POSIX" using errno.  */
  static Status POSIX_errno();

#ifdef _WIN32
  /** Construct with kind "Windows" using given GetLastError()-style value.  */
  static Status Windows(unsigned int e)
  {
    Status s(Kind::Windows);
    s.Windows_ = e;
    return s;
  }

  /** Construct with kind "Windows" using GetLastError().  */
  static Status Windows_GetLastError();
#endif

  /** Return true on "Success", false otherwise.  */
  bool IsSuccess() const { return this->Kind_ == Kind::Success; }

  /** Return true on "Success", false otherwise.  */
  explicit operator bool() const { return this->IsSuccess(); }

  /** Return the kind of status.  */
  Kind GetKind() const { return this->Kind_; }

  /** If the kind is "POSIX", returns the errno-style value.
      Otherwise, returns 0.  */
  int GetPOSIX() const
  {
    return this->Kind_ == Kind::POSIX ? this->POSIX_ : 0;
  }

#ifdef _WIN32
  /** If the kind is "Windows", returns the GetLastError()-style value.
      Otherwise, returns 0.  */
  unsigned int GetWindows() const
  {
    return this->Kind_ == Kind::Windows ? this->Windows_ : 0;
  }
#endif

  /** Return a human-readable description of the status.  */
  std::string GetString() const;

private:
  Status(Kind kind)
    : Kind_(kind)
  {
  }

  Kind Kind_ = Kind::Success;

  union
  {
    int POSIX_;
#ifdef _WIN32
    unsigned int Windows_;
#endif
  };
};

} // namespace itksys

#endif
