/**
 * (c) 2014-2016 Alexandro Sanchez Bach. All rights reserved.
 * Released under GPL v2 license. Read LICENSE for more details.
 */

#pragma once

#include "nucleus/common.h"
#include "nucleus/system/system.h"
#include "nucleus/system/scei/cellos/lv2/sys_process.h" // TODO: Just for sys_process_t

namespace sys {
namespace scei {
namespace orbis {

// Orbis Return Codes
enum {
    SCE_OK                           = 0x00000000,

    SCE_KERNEL_ERROR_UNKNOWN         = 0x80020000,
    SCE_KERNEL_ERROR_EPERM           = 0x80020001,
    SCE_KERNEL_ERROR_ENOENT          = 0x80020002,
    SCE_KERNEL_ERROR_ESRCH           = 0x80020003,
    SCE_KERNEL_ERROR_EINTR           = 0x80020004,
    SCE_KERNEL_ERROR_EIO             = 0x80020005,
    SCE_KERNEL_ERROR_ENXIO           = 0x80020006,
    SCE_KERNEL_ERROR_E2BIG           = 0x80020007,
    SCE_KERNEL_ERROR_ENOEXEC         = 0x80020008,
    SCE_KERNEL_ERROR_EBADF           = 0x80020009,
    SCE_KERNEL_ERROR_ECHILD          = 0x8002000A,
    SCE_KERNEL_ERROR_EDEADLK         = 0x8002000B,
    SCE_KERNEL_ERROR_ENOMEM          = 0x8002000C,
    SCE_KERNEL_ERROR_EACCES          = 0x8002000D,
    SCE_KERNEL_ERROR_EFAULT          = 0x8002000E,
    SCE_KERNEL_ERROR_ENOTBLK         = 0x8002000F,
    SCE_KERNEL_ERROR_EBUSY           = 0x80020010,
    SCE_KERNEL_ERROR_EEXIST          = 0x80020011,
    SCE_KERNEL_ERROR_EXDEV           = 0x80020012,
    SCE_KERNEL_ERROR_ENODEV          = 0x80020013,
    SCE_KERNEL_ERROR_ENOTDIR         = 0x80020014,
    SCE_KERNEL_ERROR_EISDIR          = 0x80020015,
    SCE_KERNEL_ERROR_EINVAL          = 0x80020016,
    SCE_KERNEL_ERROR_ENFILE          = 0x80020017,
    SCE_KERNEL_ERROR_EMFILE          = 0x80020018,
    SCE_KERNEL_ERROR_ENOTTY          = 0x80020019,
    SCE_KERNEL_ERROR_ETXTBSY         = 0x8002001A,
    SCE_KERNEL_ERROR_EFBIG           = 0x8002001B,
    SCE_KERNEL_ERROR_ENOSPC          = 0x8002001C,
    SCE_KERNEL_ERROR_ESPIPE          = 0x8002001D,
    SCE_KERNEL_ERROR_EROFS           = 0x8002001E,
    SCE_KERNEL_ERROR_EMLINK          = 0x8002001F,
    SCE_KERNEL_ERROR_EPIPE           = 0x80020020,
    SCE_KERNEL_ERROR_EDOM            = 0x80020021,
    SCE_KERNEL_ERROR_ERANGE          = 0x80020022,
    SCE_KERNEL_ERROR_EWOULDBLOCK     = 0x80020023,
    SCE_KERNEL_ERROR_EINPROGRESS     = 0x80020024,
    SCE_KERNEL_ERROR_EALREADY        = 0x80020025,
    SCE_KERNEL_ERROR_ENOTSOCK        = 0x80020026,
    SCE_KERNEL_ERROR_EDESTADDRREQ    = 0x80020027,
    SCE_KERNEL_ERROR_EMSGSIZE        = 0x80020028,
    SCE_KERNEL_ERROR_EPROTOTYPE      = 0x80020029,
    SCE_KERNEL_ERROR_ENOPROTOOPT     = 0x8002002A,
    SCE_KERNEL_ERROR_EPROTONOSUPPORT = 0x8002002B,
    SCE_KERNEL_ERROR_ESOCKTNOSUPPORT = 0x8002002C,
    SCE_KERNEL_ERROR_EOPNOTSUPP      = 0x8002002D,
    SCE_KERNEL_ERROR_EPFNOSUPPORT    = 0x8002002E,
    SCE_KERNEL_ERROR_EAFNOSUPPORT    = 0x8002002F,
    SCE_KERNEL_ERROR_EADDRINUSE      = 0x80020030,
    SCE_KERNEL_ERROR_EADDRNOTAVAIL   = 0x80020031,
    SCE_KERNEL_ERROR_ENETDOWN        = 0x80020032,
    SCE_KERNEL_ERROR_ENETUNREACH     = 0x80020033,
    SCE_KERNEL_ERROR_ENETRESET       = 0x80020034,
    SCE_KERNEL_ERROR_ECONNABORTED    = 0x80020035,
    SCE_KERNEL_ERROR_ECONNRESET      = 0x80020036,
    SCE_KERNEL_ERROR_ENOBUFS         = 0x80020037,
    SCE_KERNEL_ERROR_EISCONN         = 0x80020038,
    SCE_KERNEL_ERROR_ENOTCONN        = 0x80020039,
    SCE_KERNEL_ERROR_ESHUTDOWN       = 0x8002003A,
    SCE_KERNEL_ERROR_ETOOMANYREFS    = 0x8002003B,
    SCE_KERNEL_ERROR_ETIMEDOUT       = 0x8002003C,
    SCE_KERNEL_ERROR_ECONNREFUSED    = 0x8002003D,
    SCE_KERNEL_ERROR_ELOOP           = 0x8002003E,
    SCE_KERNEL_ERROR_ENAMETOOLONG    = 0x8002003F,
    SCE_KERNEL_ERROR_EHOSTDOWN       = 0x80020040,
    SCE_KERNEL_ERROR_EHOSTUNREACH    = 0x80020041,
    SCE_KERNEL_ERROR_ENOTEMPTY       = 0x80020042,
    SCE_KERNEL_ERROR_EPROCLIM        = 0x80020043,
    SCE_KERNEL_ERROR_EUSERS          = 0x80020044,
    SCE_KERNEL_ERROR_EDQUOT          = 0x80020045,
    SCE_KERNEL_ERROR_ESTALE          = 0x80020046,
    SCE_KERNEL_ERROR_EREMOTE         = 0x80020047,
    SCE_KERNEL_ERROR_EBADRPC         = 0x80020048,
    SCE_KERNEL_ERROR_ERPCMISMATCH    = 0x80020049,
    SCE_KERNEL_ERROR_EPROGUNAVAIL    = 0x8002004A,
    SCE_KERNEL_ERROR_EPROGMISMATCH   = 0x8002004B,
    SCE_KERNEL_ERROR_EPROCUNAVAIL    = 0x8002004C,
    SCE_KERNEL_ERROR_ENOLCK          = 0x8002004D,
    SCE_KERNEL_ERROR_ENOSYS          = 0x8002004E,
    SCE_KERNEL_ERROR_EFTYPE          = 0x8002004F,
    SCE_KERNEL_ERROR_EAUTH           = 0x80020050,
    SCE_KERNEL_ERROR_ENEEDAUTH       = 0x80020051,
    SCE_KERNEL_ERROR_EIDRM           = 0x80020052,
    SCE_KERNEL_ERROR_ENOMSG          = 0x80020053,
    SCE_KERNEL_ERROR_EOVERFLOW       = 0x80020054,
    SCE_KERNEL_ERROR_ECANCELED       = 0x80020055,
    SCE_KERNEL_ERROR_EILSEQ          = 0x80020056,
    SCE_KERNEL_ERROR_ENOATTR         = 0x80020057,
    SCE_KERNEL_ERROR_EDOOFUS         = 0x80020058,
    SCE_KERNEL_ERROR_EBADMSG         = 0x80020059,
    SCE_KERNEL_ERROR_EMULTIHOP       = 0x8002005A,
    SCE_KERNEL_ERROR_ENOLINK         = 0x8002005B,
    SCE_KERNEL_ERROR_EPROTO          = 0x8002005C,
    SCE_KERNEL_ERROR_ENOTCAPABLE     = 0x8002005D,
    SCE_KERNEL_ERROR_ECAPMODE        = 0x8002005E,
    SCE_KERNEL_ERROR_ENOBLK          = 0x8002005F,
    SCE_KERNEL_ERROR_EICV            = 0x80020060,
    SCE_KERNEL_ERROR_ENOPLAYGOENT    = 0x80020061,
};

struct OrbisSyscall {
    const char* name;
};

class OrbisOS : public System {
    OrbisSyscall syscalls[1024];

public:
    // Kernel information
    sys_process_t proc; // TODO: Is this really necessary

    OrbisOS(Emulator* emulator);

    /**
     * Start the process at the given entry point
     * @param[in]  entry  Module entry point
     */
    bool init(U64 entry);

    bool start(const std::string& path);
};

}  // namespace orbis
}  // namespace scei
}  // namespace sys
