#pragma once

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <unistd.h>

#define MODULE_VERSION_MAJ 5
#define MODULE_VERSION_MIN 0
#define MODULE_VERSION_PAT 2

/* 
 * ctors order: 
 * 0) modules_pre_start()
 * 1) modules_init()
 * 2) each module_pre_start() (only module_easy API)
 * 3) each module ctor function (only module_easy API)
 * 
 * dtors order:
 * 1) each module's dtor function (only module_easy API)
 * 0) modules_destroy()
 */
#define _ctor0_     __attribute__((constructor (110)))
#define _ctor1_     __attribute__((constructor (111)))
#define _ctor2_     __attribute__((constructor (112)))
#define _ctor3_     __attribute__((constructor (113)))
#define _dtor0_     __attribute__((destructor (110)))
#define _dtor1_     __attribute__((destructor (111)))

#define _pure_      __attribute__((pure))

#define _weak_      __attribute__((weak))
#define _public_    __attribute__ ((visibility("default")))

#define MODULES_DEFAULT_CTX  "default"
#define MODULES_MAX_EVENTS   64

/** Structs types **/

/* Incomplete structure declaration to self handler */
typedef struct _self self_t;

/* Modules states */
enum module_states { IDLE = 0x1, RUNNING = 0x2, PAUSED = 0x4, STOPPED = 0x8 };

/* PubSub message types */
enum msg_type { USER, LOOP_STARTED, LOOP_STOPPED, MODULE_STARTED, MODULE_STOPPED, MODULE_POISONPILL };

typedef struct {
    const char *topic;
    const void *message;
    ssize_t size;
    const self_t *sender;
    enum msg_type type;
} ps_msg_t;

typedef struct {
    int fd;
    const void *userptr;
} fd_msg_t;

typedef struct {
    bool is_pubsub;
    union {
        const fd_msg_t      *fd_msg;
        const ps_msg_t      *ps_msg;
    };
} msg_t;

/* Callbacks typedefs */
typedef void (*init_cb)(void);
typedef bool (*evaluate_cb)(void);
typedef void (*recv_cb)(const msg_t *const msg, const void *userdata);
typedef void (*destroy_cb)(void);

/* Logger callback */
typedef void (*log_cb)(const self_t *self, const char *fmt, va_list args, const void *userdata);

/* Memory management user-passed functions */
typedef void *(*malloc_fn)(size_t size);
typedef void *(*realloc_fn)(void *ptr, size_t size);
typedef void *(*calloc_fn)(size_t nmemb, size_t size);
typedef void (*free_fn)(void *ptr);

/* Struct that holds user defined callbacks */
typedef struct {
    init_cb init;                           // module's init function (should return a FD)
    evaluate_cb evaluate;                   // module's state changed function
    recv_cb recv;                           // module's recv function
    destroy_cb destroy;                     // module's destroy function
} userhook_t;

/* Struct that holds user defined memory functions */
typedef struct {
    malloc_fn _malloc;
    realloc_fn _realloc;
    calloc_fn _calloc;
    free_fn _free;
} memhook_t;

/* Module return codes */
typedef enum {
    MOD_REF_ERR = -9,
    MOD_WRONG_PARAM,
    MOD_NO_MEM,
    MOD_WRONG_STATE,
    MOD_NO_PARENT,
    MOD_NO_CTX,
    MOD_NO_MOD,
    MOD_NO_SELF,
    MOD_ERR,
    MOD_OK
} module_ret_code;
