#pragma once

// pqrs::osx::kern_return v1.0

// (C) Copyright Takayama Fumihiko 2020.
// Distributed under the Boost Software License, Version 1.0.
// (See http://www.boost.org/LICENSE_1_0.txt)

#include <iostream>
#include <mach/error.h>
#include <mach/kern_return.h>
#include <string>

namespace pqrs {
namespace osx {
class kern_return final {
public:
  kern_return(kern_return_t kr) : kr_(kr) {
  }

  kern_return_t get(void) const {
    return kr_;
  }

  std::string to_string(void) const {
#define PQRS_OSX_KERN_RETURN_TO_STRING(KR) \
  case KR:                                 \
    return #KR;

    switch (err_get_code(kr_)) {
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_SUCCESS);

      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_ADDRESS);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_PROTECTION_FAILURE);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_NO_SPACE);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_ARGUMENT);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_FAILURE);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_RESOURCE_SHORTAGE);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_NOT_RECEIVER);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_NO_ACCESS);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_MEMORY_FAILURE);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_MEMORY_ERROR);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_ALREADY_IN_SET);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_NOT_IN_SET);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_NAME_EXISTS);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_ABORTED);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_NAME);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_TASK);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_RIGHT);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_VALUE);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_UREFS_OVERFLOW);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_CAPABILITY);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_RIGHT_EXISTS);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_HOST);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_MEMORY_PRESENT);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_MEMORY_DATA_MOVED);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_MEMORY_RESTART_COPY);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_PROCESSOR_SET);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_POLICY_LIMIT);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_POLICY);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_OBJECT);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_ALREADY_WAITING);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_DEFAULT_SET);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_EXCEPTION_PROTECTED);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_LEDGER);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_MEMORY_CONTROL);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INVALID_SECURITY);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_NOT_DEPRESSED);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_TERMINATED);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_LOCK_SET_DESTROYED);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_LOCK_UNSTABLE);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_LOCK_OWNED);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_LOCK_OWNED_SELF);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_SEMAPHORE_DESTROYED);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_RPC_SERVER_TERMINATED);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_RPC_TERMINATE_ORPHAN);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_RPC_CONTINUE_ORPHAN);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_NOT_SUPPORTED);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_NODE_DOWN);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_NOT_WAITING);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_OPERATION_TIMED_OUT);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_CODESIGN_ERROR);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_POLICY_STATIC);
      PQRS_OSX_KERN_RETURN_TO_STRING(KERN_INSUFFICIENT_BUFFER_SIZE);
    }

#undef PQRS_OSX_KERN_RETURN_TO_STRING

    return std::string("Unknown kern_return_t (") + std::to_string(kr_) + ")";
  }

  bool success(void) const {
    return kr_ == KERN_SUCCESS;
  }

  operator bool(void) const {
    return success();
  }

private:
  kern_return_t kr_;
};

inline std::ostream& operator<<(std::ostream& stream, const kern_return& value) {
  return stream << value.to_string();
}
} // namespace osx
} // namespace pqrs
