#include "VulkanDebugManager.h"

#include "utilities/Logger.h"

VulkanDebugManager::VulkanDebugManager()
{
}

VulkanDebugManager::~VulkanDebugManager()
{
}

void VulkanDebugManager::Initialize(VkInstance Instance)
{
	if (IsInitialized())
	{
		return;
	}

	this->Instance = Instance;
	SetupDebugMessanger();
}

void VulkanDebugManager::Cleanup()
{
	if (!IsInitialized())
	{
		return;
	}

	FDestroyParams Params = { Instance, DebugMessenger, nullptr };
	DestroyDebugUtilsMessengerExt(Params);
	DebugMessenger = VK_NULL_HANDLE;
}

VkResult VulkanDebugManager::CreateDebugUtilsMessengerExt(const FCreateParams& Params)
{
	auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Params.Instance, "vkCreateDebugUtilsMessengerEXT");
	if (func != nullptr)
	{
		return func(Params.Instance, Params.pCreateInfo, Params.pAllocator, Params.pDebugMessenger);
	}
	else
	{
		return VK_ERROR_EXTENSION_NOT_PRESENT;
	}
}

void VulkanDebugManager::DestroyDebugUtilsMessengerExt(const FDestroyParams& Params)
{
	auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
		Params.Instance,
		"vkDestroyDebugUtilsMessengerEXT");

	if (func != nullptr)
	{
		func(Params.Instance, Params.DebugMessenger, Params.pAllocator);
	}
}

VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugManager::DebugCallback(
	VkDebugUtilsMessageSeverityFlagBitsEXT		MessageSeverity,
	VkDebugUtilsMessageTypeFlagsEXT				MessageType,
	const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
	void*										pUserData)
{
	Log::Validation(pCallbackData->pMessage);

	if (MessageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
	{
	}

	return VK_FALSE;
}

void VulkanDebugManager::PopulateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo)
{
	createInfo = {};
	createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
	createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
	createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
	createInfo.pfnUserCallback = VulkanDebugManager::DebugCallback;
}

void VulkanDebugManager::SetupDebugMessanger()
{
	VkDebugUtilsMessengerCreateInfoEXT CreateInfo;

	PopulateDebugMessengerCreateInfo(CreateInfo);

	FCreateParams Params = { Instance, &CreateInfo, nullptr, &DebugMessenger };

	if (CreateDebugUtilsMessengerExt(Params) != VK_SUCCESS)
	{
		Log::Error("Failed to set up debug messenger!");
	}
}
