#include "swapchain.h"
#include "swapchain_creator.h"
#include "device.h"
#include "image.h"
#include "../backend.h"
#include "../thread/worker.h"
#include "../vulkan_context.h"
#include "zlog.h"
namespace vulkanapi {
	Swapchain::Swapchain(SwapchainCreator& Creator)
		: mPtr(nullptr)
		, mDevice(Creator.device)
	{
		VkSurfaceCapabilitiesKHR capabilities{};
		vkGetPhysicalDeviceSurfaceCapabilitiesKHR(Creator.device.GetPhysical(), Creator.presentation_surface, &capabilities);
		VkExtent2D image_extent = Creator.EnableImageExtent2D(capabilities);
		VkSwapchainCreateInfoKHR swapchain_create_info = {
			VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,// VkStructureType                  sType
			nullptr,                                    // const void                     * pNext
			0,                                          // VkSwapchainCreateFlagsKHR        flags
			Creator.presentation_surface,               // VkSurfaceKHR                     surface
			(uint32_t)Creator.frames,                   // uint32_t                         minImageCount
			Creator.imageFormat,                        // VkFormat                         imageFormat
			Creator.imageColorSpace,                    // VkColorSpaceKHR                  imageColorSpace
			image_extent,                               // VkExtent2D                       imageExtent
			1,                                          // uint32_t                         imageArrayLayers
			Creator.imageUsage,                         // VkImageUsageFlags                imageUsage
			VK_SHARING_MODE_EXCLUSIVE,                  // VkSharingMode                    imageSharingMode
			0,                                          // uint32_t                         queueFamilyIndexCount
			nullptr,                                    // const uint32_t                 * pQueueFamilyIndices
			capabilities.currentTransform,              // VkSurfaceTransformFlagBitsKHR    preTransform
			VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,          // VkCompositeAlphaFlagBitsKHR      compositeAlpha
			Creator.presentMode,                        // VkPresentModeKHR                 presentMode
			VK_TRUE,                                    // VkBool32                         clipped
			VK_NULL_HANDLE                              // VkSwapchainKHR                   oldSwapchain
		};
		VkResult result = vkCreateSwapchainKHR(Creator.device.Ptr(), &swapchain_create_info, nullptr, &mPtr);
		if (result != VK_SUCCESS) {
			zlog::error("Failed to create swap chain.");
		}
		vector<VkImage> swapchain_images;
		Creator.CreateSwapchainImages(mPtr, swapchain_images);
		auto args = Image::Make2DArgs(Creator.width, Creator.height, Creator.imageFormat, VK_SAMPLE_COUNT_8_BIT, Creator.imageUsage, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE);
		args.Sharing = VK_SHARING_MODE_EXCLUSIVE;
		for (int i = 0; i < Creator.frames;i++) {
			mSurfaces.push_back(new Image(Creator.device,"swapchain" + to_string(i), swapchain_images[i], args));
		}
		mSurfaceSemaphore = Creator.device.CreateSemaphore();
		mRenderSemaphore = Creator.device.CreateSemaphore();
	}
	void Swapchain::Aquire(VulkanContext& ctx)
	{
		ctx.surfaceSemaphore = mSurfaceSemaphore;
		vkAcquireNextImageKHR(mDevice.Ptr(), mPtr, UINT64_MAX, ctx.surfaceSemaphore, VK_NULL_HANDLE, &ctx.frame);
	}
	void Swapchain::Present(VulkanContext& ctx)
	{
		VkSwapchainKHR swapChains[] = { mPtr };
		VkSemaphore waitSemaphores[] = { ctx.surfaceSemaphore };
		VkPresentInfoKHR presentInfo = {};
		presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
		presentInfo.pWaitSemaphores = waitSemaphores;
		presentInfo.waitSemaphoreCount = 1;
		presentInfo.pSwapchains = swapChains;
		presentInfo.swapchainCount = 1;
		presentInfo.pImageIndices = &ctx.frame;
		presentInfo.pResults = VK_NULL_HANDLE;
		Backend::RenderWorker->Present(presentInfo);
	}
}
