extern "C" {
#include "dittoffi.h"
#include <android/log.h>
}

// This include must be outside the extern C block since it requires C++ linkage
#include <exception>

#ifdef SWIG
%feature("director", assumeoverride=1) LoggerCb;
#endif
class LoggerCb {
public:
    virtual ~LoggerCb() {
        unregisterCustomLogCb();
    }

    virtual void ffiCustomLog(CLogLevel_t, char const*) = 0;

    void registerCustomLogCb () {
        LoggerCb::virtual_instance = this;
        ditto_logger_set_custom_log_cb(LoggerCb::invokeFfiCustomLog);
    }

    static void unregisterCustomLogCb () {
        ditto_logger_set_custom_log_cb(nullptr);
    }

private:
    static LoggerCb * virtual_instance;
    static void invokeFfiCustomLog(CLogLevel_t c_log_level, char * msg) {
        return LoggerCb::virtual_instance->ffiCustomLog_shim(c_log_level, msg);
    }

    // Local shim, responsible for freeing the msg after each InternalDittoLogger.ffiCustomLog() call.
    void ffiCustomLog_shim(CLogLevel_t c_log_level, char * msg) {
        try {
            ffiCustomLog(c_log_level, msg);
        } catch (std::exception const &e) {
            // https://developer.android.com/ndk/reference/group/logging#__android_log_print
            __android_log_print(ANDROID_LOG_ERROR, "LoggerCb",
                                "ffiCustomLog_shim: Custom log callback threw exception: %s\n",
                                e.what());
        }
        ditto_c_string_free(msg);
    }
};
