#ifndef SCENE_NODE_ENTITY_H
#define SCENE_NODE_ENTITY_H

#include "utils/mirror.h"
#include "utils/drop.h"

struct SceneNode;

typedef struct ISceneNodeEntity {
    void(*const enter_tree)(void *self);
    void(*const exit_tree)(void *self);
    void(*const tick)(void *self, double delta);
    struct SceneNode *(*const get_node)(void *self);
    void (*const set_node)(void *self, struct SceneNode *node);
} ISceneNodeEntity;

typedef struct SceneNodeEntity {
    ISceneNodeEntity const *tc;
    void *data;
    IMirror const *mirror;
    IDrop const *drop;
} SceneNodeEntity;

#define impl_SceneNodeEntity_defaults(T)\
static void T##_default_enter_tree(T *self) {}\
static void T##_default_exit_tree(T *self) {}\
static void T##_default_tick(T *self, double delta) {}

//! Implement SceneNodeEntity for a struct.
//! IMPORTANT: requires Mirror and Drop to be implemented,
//! as well as a `SceneNode *node` member on T.
//! Generates functions called T##_get_node_GEN_ and T##_set_node_GEN_ as getter and setter for that member.
#define impl_SceneNodeEntity_for(T, enter_tree_f, exit_tree_f, tick_f)\
static struct SceneNode *T##_get_node_GEN_(T *self) { return self->node; }\
static void T##_set_node_GEN_(T *self, struct SceneNode *node) { self->node = node; }\
SceneNodeEntity T##_as_SceneNodeEntity(T *x) {\
    TC_FN_TYPECHECK(void, enter_tree_f, T*);\
    TC_FN_TYPECHECK(void, exit_tree_f, T*);\
    TC_FN_TYPECHECK(void, tick_f, T*, double);\
    static ISceneNodeEntity const tc = {\
        .enter_tree     = (void(*const)(void*))                     enter_tree_f,\
        .exit_tree      = (void(*const)(void*))                     exit_tree_f,\
        .tick           = (void(*const)(void*,double))              tick_f,\
        .get_node       = (struct SceneNode *(*const)(void*))       T##_get_node_GEN_,\
        .set_node       = (void (*const)(void*, struct SceneNode*)) T##_set_node_GEN_\
    };\
    SceneNodeEntity e = { .tc = &tc, .data = x, .mirror = T##_as_Mirror(x).tc, .drop = T##_as_Drop(x).tc };\
    return e;\
}

#endif // !SCENE_NODE_ENTITY_H
