/*  Copyright (C) 2015  Povilas Kanapickas <povilas@radix.lt>

    This file is part of cppreference-doc

    This work is licensed under the Creative Commons Attribution-ShareAlike 3.0
    Unported License. To view a copy of this license, visit
    http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative
    Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.

    Permission is granted to copy, distribute and/or modify this document
    under the terms of the GNU Free Documentation License, Version 1.3 or
    any later version published by the Free Software Foundation; with no
    Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
*/

#ifndef CPPREFERENCE_SYSTEM_ERROR_H
#define CPPREFERENCE_SYSTEM_ERROR_H

#if CPPREFERENCE_STDVER>= 2011

namespace std {

class error_category {
public:
    error_category(const error_category& other) = delete;
#if CPPREFERENCE_STDVER>= 2014
    constexpr error_category();
#endif
    virtual ~error_category();
    virtual const char* name() const = 0;
    virtual std::error_condition default_error_condition(int code) const;
    virtual bool equivalent(int code,
                            const std::error_condition& condition) const;
    virtual bool equivalent(const std::error_code& code,
                            int condition) const;
    virtual std::string message(int condition) const = 0;

    bool operator==(const error_category& rhs) const;
    bool operator!=(const error_category& rhs) const;
    bool operator<(const error_category& rhs) const;
};

const std::error_category& generic_category();
const std::error_category& system_category();

class error_condition {
public:

    error_condition();
    error_condition(const error_condition& other);
    error_condition(int val, const error_category& cat);

    template<class ErrorConditionEnum>
    error_condition(ErrorConditionEnum e);

    error_condition& operator=(const error_condition& other);

    template<class ErrorConditionEnum>
    error_condition& operator=(ErrorConditionEnum e);

    void assign(int val, const error_category& cat);

    void clear();

    int value() const;

    const error_category& category() const;

    std::string message() const;

    explicit operator bool() const;
};

bool operator==(const error_condition& lhs, const error_condition& rhs);
bool operator==(const error_code& lhs, const error_condition& rhs);
bool operator==(const error_condition& lhs, const error_code& rhs);
bool operator!=(const error_condition& lhs, const error_condition& rhs);
bool operator!=(const error_code& lhs, const error_condition& rhs);
bool operator!=(const error_condition& lhs, const error_code& rhs);
bool operator<(const error_condition& lhs, const error_condition& rhs);

enum class errc {
    address_family_not_supported,       //  EAFNOSUPPORT
    address_in_use,                     //  EADDRINUSE
    address_not_available,              //  EADDRNOTAVAIL
    already_connected,                  //  EISCONN
    argument_list_too_long,             //  E2BIG
    argument_out_of_domain,             //  EDOM
    bad_address,                        //  EFAULT
    bad_file_descriptor,                //  EBADF
    bad_message,                        //  EBADMSG
    broken_pipe,                        //  EPIPE
    connection_aborted,                 //  ECONNABORTED
    connection_already_in_progress,     //  EALREADY
    connection_refused,                 //  ECONNREFUSED
    connection_reset,                   //  ECONNRESET
    cross_device_link,                  //  EXDEV
    destination_address_required,       //  EDESTADDRREQ
    device_or_resource_busy,            //  EBUSY
    directory_not_empty,                //  ENOTEMPTY
    executable_format_error,            //  ENOEXEC
    file_exists,                        //  EEXIST
    file_too_large,                     //  EFBIG
    filename_too_long,                  //  ENAMETOOLONG
    function_not_supported,             //  ENOSYS
    host_unreachable,                   //  EHOSTUNREACH
    identifier_removed,                 //  EIDRM
    illegal_byte_sequence,              //  EILSEQ
    inappropriate_io_control_operation, //  ENOTTY
    interrupted,                        //  EINTR
    invalid_argument,                   //  EINVAL
    invalid_seek,                       //  ESPIPE
    io_error,                           //  EIO
    is_a_directory,                     //  EISDIR
    message_size,                       //  EMSGSIZE
    network_down,                       //  ENETDOWN
    network_reset,                      //  ENETRESET
    network_unreachable,                //  ENETUNREACH
    no_buffer_space,                    //  ENOBUFS
    no_child_process,                   //  ECHILD
    no_link,                            //  ENOLINK
    no_lock_available,                  //  ENOLCK
    no_message_available,               //  ENODATA
    no_message,                         //  ENOMSG
    no_protocol_option,                 //  ENOPROTOOPT
    no_space_on_device,                 //  ENOSPC
    no_stream_resources,                //  ENOSR
    no_such_device_or_address,          //  ENXIO
    no_such_device,                     //  ENODEV
    no_such_file_or_directory,          //  ENOENT
    no_such_process,                    //  ESRCH
    not_a_directory,                    //  ENOTDIR
    not_a_socket,                       //  ENOTSOCK
    not_a_stream,                       //  ENOSTR
    not_connected,                      //  ENOTCONN
    not_enough_memory,                  //  ENOMEM
    not_supported,                      //  ENOTSUP
    operation_canceled,                 //  ECANCELED
    operation_in_progress,              //  EINPROGRESS
    operation_not_permitted,            //  EPERM
    operation_not_supported,            //  EOPNOTSUPP
    operation_would_block,              //  EWOULDBLOCK
    owner_dead,                         //  EOWNERDEAD
    permission_denied,                  //  EACCES
    protocol_error,                     //  EPROTO
    protocol_not_supported,             //  EPROTONOSUPPORT
    read_only_file_system,              //  EROFS
    resource_deadlock_would_occur,      //  EDEADLK
    resource_unavailable_try_again,     //  EAGAIN
    result_out_of_range,                //  ERANGE
    state_not_recoverable,              //  ENOTRECOVERABLE
    stream_timeout,                     //  ETIME
    text_file_busy,                     //  ETXTBSY
    timed_out,                          //  ETIMEDOUT
    too_many_files_open_in_system,      //  ENFILE
    too_many_files_open,                //  EMFILE
    too_many_links,                     //  EMLINK
    too_many_symbolic_link_levels,      //  ELOOP
    value_too_large,                    //  EOVERFLOW
    wrong_protocol_type,                //  EPROTOTYPE
};

class error_code {
public:
    error_code();
    error_code(int ec, const error_category& ecat);
    template<class ErrorCodeEnum>
    error_code(ErrorCodeEnum e);

    template<class ErrorCodeEnum>
    error_code& operator=(ErrorCodeEnum e);

    void assign(int ec, const error_category& ecat);
    void clear();
    int value() const;

    const std::error_category& category() const;
    std::error_condition default_error_condition() const;

    std::string message() const;
    explicit operator bool() const;
};

bool operator==(const error_code& lhs, const error_code& rhs);
bool operator!=(const error_code& lhs, const error_code& rhs);
bool operator<(const error_code& lhs, const error_code& rhs);

template<class CharT, class Traits>
std::basic_ostream<CharT, Traits>&
operator<<(basic_ostream<CharT, Traits>& os, const error_code& ec);

class system_error : public runtime_error {
public:
    system_error(std::error_code ec);
    system_error(std::error_code ec, const std::string& what_arg);
    system_error(std::error_code ec, const char* what_arg);
    system_error(int ev, const std::error_category& ecat);
    system_error(int ev, const std::error_category& ecat,
                 const std::string& what_arg);
    system_error(int ev, const std::error_category& ecat,
                 const char* what_arg);

    const std::error_code& code() const;

    virtual const char* what() const;
};

template<class T>
struct is_error_code_enum : integral_constant<bool, false> {};
template<class T>
struct is_error_condition_enum : integral_constant<bool, false> {};

std::error_code make_error_code(std::errc e);
std::error_condition make_error_condition(std::errc e);

} // namespace std

#endif // CPPREFERENCE_STDVER>= 2011

#endif // CPPREFERENCE_SYSTEM_ERROR_H
