#include "bluespy.h"
#include <string.h>

void callback(bluespy_event_id id);

#ifndef EXPORT
#if defined _WIN32
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __attribute__((visibility("default")))
#endif
#endif

bool my_global;

// The function `init` is called when blueSPY starts up. We register our callbacks then
EXPORT void init() { bluespy_register_event_callback(bluespy_event_bt_baseband, callback); }
// The function `reset` is called when blueSPY starts a new capture. Use it to reset any global
// state you have. If you have no global state, you don't need to provide this funtion
EXPORT void reset() { my_global = true; }

// We are defining our own event type so we can attach some extra data to the event
// You likely won't need to do this and can just use bluespy_custom_event directly
// You may want the extra data to record the state of a state machine when the packet arrived
// or to perform a computation only once (rather than each time `query` is called)
typedef struct MyCustomEvent {
    bluespy_custom_event event;
    const char* str;
} MyCustomEvent;

// Queries are how blueSPY will get information from your custom event to show in the UI
// You don't have to implement any queries
bluespy_query_value query(const bluespy_custom_event* self_, const char* query,
                          bool prefer_string) {
    MyCustomEvent* self = (MyCustomEvent*)self_;
    if (strcmp(query, "summary") == 0) {
        // The summary query is used to determine what to show in the summary column
        return (bluespy_query_value){.s = self->str, .type = bluespy_query_type_string};
    } else if (strcmp(query, "details") == 0) {
        // The "details" query is a special query for custom events
        // It needs to return a specific json structure which is used to determine what to show in
        // the details tab
        return (bluespy_query_value){
            .s = "[{\"name\": \"Foo\", \"value\": 10, \"bitpos\": 0, \"bitwidth\": 8},"
                 "{\"name\": \"Bar\", \"bitpos\": 8, \"value\": "
                 "[{\"name\": \"Baz\", \"value\": \"Qux\", \"bitpos\": 0, \"bitwidth\": 8},"
                 "{\"name\": \"Quux\", \"value\": true, \"bitpos\": 8, \"bitwidth\": 16}]}]",
            .type = bluespy_query_type_string};
    } else if (strcmp(query, "time") == 0) {
        // We can return other types, giving them a string representation is optional.
        // If you want default string formatting, return bluespy_query_type_int even when
        // prefer_string is true.
        if (prefer_string)
            return (bluespy_query_value){.s = "3 O'Clock on a tuesday",
                                         .type = bluespy_query_type_string};
        else
            return (bluespy_query_value){.i = 1234, .type = bluespy_query_type_int};
    } else if (strcmp(query, "payload") == 0) {
        // Just use the payload from the child. This example is the same as the default behaviour;
        // not returning anything for "payload" will use the child's payload. If we had multiple
        // children we could join up the payloads or something more interesting here
        return (bluespy_query_value){.type = bluespy_query_type_bytes,
                                     .bytes =
                                         bluespy_query_bytes(self->event.children[0], "payload")};
    } else if (strcmp(query, "custom_source") == 0) {
        // This is useful when you have multiple custom decoders and want to identify where a custom
        // event has come from. This is necessary when you have custom decoder that act on custom
        // events (such as "example_custom_decoder.cpp") so that they don't trigger on themselves
        return (bluespy_query_value){.s = "example_custom_decoder.c",
                                     .type = bluespy_query_type_string};
    } else {
        // Return nothing for all other queries
        return (bluespy_query_value){.type = bluespy_query_type_none};
    }
}

void callback(bluespy_event_id id) {
    MyCustomEvent* event = bluespy_allocate(sizeof(MyCustomEvent), NULL);
    char key[] = {0x3F, 0x49, 0xF6, 0xD4, 0xA3, 0xC5, 0x5F, 0x38, 0x74, 0xC9, 0xB3,
                  0xE3, 0xD2, 0x10, 0x3F, 0x50, 0x4A, 0xFF, 0x60, 0x7B, 0xEB, 0x40,
                  0xB7, 0x99, 0x58, 0x99, 0xB8, 0xA6, 0xCD, 0x3C, 0x1A, 0xBD};
    bluespy_mark_key_used(key, 32);

    event->event.children = bluespy_allocate(sizeof(bluespy_event_id), NULL);
    event->event.children[0] = id;
    event->event.n_children = 1;
    event->event.query = query;
    const char* str = "Hello world from C!";
    if (my_global) {
        str = "Hello world from C! I am the first packet!!!";
        my_global = false;
    }
    event->str = bluespy_allocate(sizeof(char) * (strlen(str) + 1), NULL);
    strcpy((char*)(event->str), str);

    bluespy_add_event(&event->event);
}
