// Copyright 2011-2025 Molecular Matters GmbH, all rights reserved.

#pragma once

#include "LPP_API_Helpers.h"


// ------------------------------------------------------------------------------------------------
// HOOKS
// ------------------------------------------------------------------------------------------------

// Registers a hook with any signature in any section.
#if defined(__clang__)
#	define LPP_HOOK(_section, _function, ...)																												\
		extern void (* const LPP_IDENTIFIER(LPP_CONCATENATE(lpp_hook_function, _function)))(__VA_ARGS__) __attribute__((section(_section)));				\
		extern void (* const LPP_IDENTIFIER(LPP_CONCATENATE(lpp_hook_function, _function)))(__VA_ARGS__) __attribute__((section(_section))) = &_function
#elif defined(_MSC_VER)
#	define LPP_HOOK(_section, _function, ...)																																				\
		__pragma(section(_section, read)) __declspec(allocate(_section)) extern void (* const LPP_IDENTIFIER(LPP_CONCATENATE(lpp_hook_function, _function)))(__VA_ARGS__) = &_function
#else
#	error("Live++: Unknown compiler.");
#endif


// Define names for the individual hook sections.
#define LPP_PRECOMPILE_HOOK_SECTION						".lpp_precompile_hooks"
#define LPP_POSTCOMPILE_HOOK_SECTION					".lpp_postcompile_hooks"

#define LPP_COMPILE_START_HOOK_SECTION					".lpp_compile_start_hooks"
#define LPP_COMPILE_SUCCESS_HOOK_SECTION				".lpp_compile_success_hooks"
#define LPP_COMPILE_ERROR_HOOK_SECTION					".lpp_compile_error_hooks"

#define LPP_LINK_START_HOOK_SECTION						".lpp_link_start_hooks"
#define LPP_LINK_SUCCESS_HOOK_SECTION					".lpp_link_success_hooks"
#define LPP_LINK_ERROR_HOOK_SECTION						".lpp_link_error_hooks"

#define LPP_HOTRELOAD_PREPATCH_HOOK_SECTION				".lpp_hotreload_prepatch_hooks"
#define LPP_HOTRELOAD_POSTPATCH_HOOK_SECTION			".lpp_hotreload_postpatch_hooks"

#define LPP_GLOBAL_HOTRELOAD_START_HOOK_SECTION			".lpp_global_hotreload_start_hooks"
#define LPP_GLOBAL_HOTRELOAD_END_HOOK_SECTION			".lpp_global_hotreload_end_hooks"


// Define ID types to uniquely identify hook function signatures.
LPP_NAMESPACE_BEGIN

typedef struct LppPrecompileHookId { char unused; } LppPrecompileHookId;
typedef struct LppPostcompileHookId { char unused; } LppPostcompileHookId;

typedef struct LppCompileStartHookId { char unused; } LppCompileStartHookId;
typedef struct LppCompileSuccessHookId { char unused; } LppCompileSuccessHookId;
typedef struct LppCompileErrorHookId { char unused; } LppCompileErrorHookId;

typedef struct LppLinkStartHookId { char unused; } LppLinkStartHookId;
typedef struct LppLinkSuccessHookId { char unused; } LppLinkSuccessHookId;
typedef struct LppLinkErrorHookId { char unused; } LppLinkErrorHookId;

typedef struct LppHotReloadPrepatchHookId { char unused; } LppHotReloadPrepatchHookId;
typedef struct LppHotReloadPostpatchHookId { char unused; } LppHotReloadPostpatchHookId;

typedef struct LppGlobalHotReloadStartHookId { char unused; } LppGlobalHotReloadStartHookId;
typedef struct LppGlobalHotReloadEndHookId { char unused; } LppGlobalHotReloadEndHookId;

LPP_NAMESPACE_END


// Registers a pre-compile hook.
#define LPP_PRECOMPILE_HOOK(_function)					LPP_HOOK(LPP_PRECOMPILE_HOOK_SECTION, _function, LPP_NAMESPACE LppPrecompileHookId, const wchar_t* const recompiledModulePath, unsigned int filesToCompileCount)

// Registers a post-compile hook.
#define LPP_POSTCOMPILE_HOOK(_function)					LPP_HOOK(LPP_POSTCOMPILE_HOOK_SECTION, _function, LPP_NAMESPACE LppPostcompileHookId, const wchar_t* const recompiledModulePath, unsigned int filesToCompileCount)


// Registers a compile start hook.
#define LPP_COMPILE_START_HOOK(_function)				LPP_HOOK(LPP_COMPILE_START_HOOK_SECTION, _function, LPP_NAMESPACE LppCompileStartHookId, const wchar_t* const recompiledModulePath, const wchar_t* const recompiledSourcePath)

// Registers a compile success hook.
#define LPP_COMPILE_SUCCESS_HOOK(_function)				LPP_HOOK(LPP_COMPILE_SUCCESS_HOOK_SECTION, _function, LPP_NAMESPACE LppCompileSuccessHookId, const wchar_t* const recompiledModulePath, const wchar_t* const recompiledSourcePath)

// Registers a compile error hook.
#define LPP_COMPILE_ERROR_HOOK(_function)				LPP_HOOK(LPP_COMPILE_ERROR_HOOK_SECTION, _function, LPP_NAMESPACE LppCompileErrorHookId, const wchar_t* const recompiledModulePath, const wchar_t* const recompiledSourcePath, const wchar_t* const compilerOutput)


// Registers a link start hook.
#define LPP_LINK_START_HOOK(_function)					LPP_HOOK(LPP_LINK_START_HOOK_SECTION, _function, LPP_NAMESPACE LppLinkStartHookId, const wchar_t* const recompiledModulePath)

// Registers a link success hook.
#define LPP_LINK_SUCCESS_HOOK(_function)				LPP_HOOK(LPP_LINK_SUCCESS_HOOK_SECTION, _function, LPP_NAMESPACE LppLinkSuccessHookId, const wchar_t* const recompiledModulePath)

// Registers a link error hook.
#define LPP_LINK_ERROR_HOOK(_function)					LPP_HOOK(LPP_LINK_ERROR_HOOK_SECTION, _function, LPP_NAMESPACE LppLinkErrorHookId, const wchar_t* const recompiledModulePath, const wchar_t* const linkerOutput)


// Registers a hot-reload pre-patch hook.
#define LPP_HOTRELOAD_PREPATCH_HOOK(_function)			LPP_HOOK(LPP_HOTRELOAD_PREPATCH_HOOK_SECTION, _function, LPP_NAMESPACE LppHotReloadPrepatchHookId, const wchar_t* const recompiledModulePath, const wchar_t* const* const modifiedFiles, unsigned int modifiedFilesCount, const wchar_t* const* const modifiedClassLayouts, unsigned int modifiedClassLayoutsCount)

// Registers a hot-reload post-patch hook.
#define LPP_HOTRELOAD_POSTPATCH_HOOK(_function)			LPP_HOOK(LPP_HOTRELOAD_POSTPATCH_HOOK_SECTION, _function, LPP_NAMESPACE LppHotReloadPostpatchHookId, const wchar_t* const recompiledModulePath, const wchar_t* const* const modifiedFiles, unsigned int modifiedFilesCount, const wchar_t* const* const modifiedClassLayouts, unsigned int modifiedClassLayoutsCount)


// Registers a global hot-reload start hook.
#define LPP_GLOBAL_HOTRELOAD_START_HOOK(_function)		LPP_HOOK(LPP_GLOBAL_HOTRELOAD_START_HOOK_SECTION, _function, LPP_NAMESPACE LppGlobalHotReloadStartHookId)

// Registers a global hot-reload end hook.
#define LPP_GLOBAL_HOTRELOAD_END_HOOK(_function)		LPP_HOOK(LPP_GLOBAL_HOTRELOAD_END_HOOK_SECTION, _function, LPP_NAMESPACE LppGlobalHotReloadEndHookId)
