#ifndef A51A04C1_ABD6_4DE9_B16A_49A9DA46C67E
#define A51A04C1_ABD6_4DE9_B16A_49A9DA46C67E

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C"
{
#endif

typedef enum
{
    mana_custom,
    mana_uint8,
    mana_sint8,
    mana_uint16,
    mana_sint16,
    mana_uint32,
    mana_sint32,
    mana_uint64,
    mana_sint64,
    mana_float,
    mana_double,
} mana_data_type_t;

// Offset based pointer. Allows to memcpy() structures with these pointers
// inside as long as the range covered by the pointers is also copied.
//
// Raw pointer value is '&ptr + offset'. nullptr is defined as offset=1.
// => Cannot point to the first byte of the struct itself but that's fine.
// Do not create temporaries of these. The offset will then be relative to the
// temporary on the stack! Do not copy these unless you copy the full memory
// range so that the offset_ptr_t in the new location stays valid.
typedef struct
{
    mana_data_type_t data_type;
    ptrdiff_t offset;
} mana_offset_ptr_t;

// Typed offset pointer based array. Stores the array size in bytes instead of
// elements to allow storing any type using mana_custom.
typedef struct
{
    mana_offset_ptr_t ptr;
    size_t size_bytes;
} mana_offset_array_t;

typedef enum
{
    mana_status_ok,
    mana_status_invalid_argument,
    mana_status_internal_error,
} mana_status_code_t;

typedef struct
{
    mana_status_code_t code;
    char message[256];
} mana_status_t;

#define MANA_DEFINE_PLUGIN_INIT(name) void *name(int plugin_argc, const char **plugin_argv)

#define MANA_DEFINE_PLUGIN_SHUTDOWN(name) void name(void *context)

#define MANA_DEFINE_PLUGIN_BEGIN_RUN(name)                                                         \
    mana_status_t name(void *context, const char *descriptor_json)

#define MANA_DEFINE_PLUGIN_END_RUN(name)                                                           \
    mana_status_t name(void *context, const char *descriptor_json)

#define MANA_DEFINE_PLUGIN_EVENT_DATA(name)                                                        \
    void name(void *context, uint16_t eventIndex, mana_offset_array_t *arrays, size_t arrayCount,  \
              size_t totalBytes)

#define MANA_DEFINE_PLUGIN_SYSTEM_EVENT(name)                                                      \
    void name(void *context, const uint32_t *data, size_t size)

typedef MANA_DEFINE_PLUGIN_INIT(mana_init_t);
typedef MANA_DEFINE_PLUGIN_SHUTDOWN(mana_shutdown_t);
typedef MANA_DEFINE_PLUGIN_BEGIN_RUN(mana_begin_run_t);
typedef MANA_DEFINE_PLUGIN_END_RUN(mana_end_run_t);
typedef MANA_DEFINE_PLUGIN_EVENT_DATA(mana_process_event_t);
typedef MANA_DEFINE_PLUGIN_SYSTEM_EVENT(mana_process_system_event_t);

typedef struct
{
    mana_init_t *init;
    mana_shutdown_t *shutdown;
    mana_begin_run_t *begin_run;
    mana_end_run_t *end_run;
    mana_process_event_t *process_event;
    mana_process_system_event_t *process_system_event;
} mana_sink_plugin_t;

// use this to define the entry point into the plugin
// from c++: extern "C" MANA_C_SINK_PLUGIN() { ... return plugin; }
#define MANA_C_SINK_PLUGIN mana_sink_plugin_t mana_get_sink_plugin

#ifdef __cplusplus
}
#endif

#endif /* A51A04C1_ABD6_4DE9_B16A_49A9DA46C67E */
