#include <GLFW/glfw3.h>

#include "precomp.h"
#include "vulkan/graphics.h"

namespace veng {

Graphics::Graphics(gsl::not_null<Window*> window) : window_(window) {
#if !defined(NDEBUG)
  validation_enabled_ = true;
#endif
  InitializeVulkan();
}

Graphics::~Graphics() {
  if (logical_device_ != VK_NULL_HANDLE) {
    vkDeviceWaitIdle(logical_device_);
    CleanupSwapChain();

    if (texture_pool_ != VK_NULL_HANDLE)
      vkDestroyDescriptorPool(logical_device_, texture_pool_, nullptr);

    if (texture_set_layout_ != VK_NULL_HANDLE)
      vkDestroyDescriptorSetLayout(logical_device_, texture_set_layout_,
                                   nullptr);

    if (texture_sampler_ != VK_NULL_HANDLE)
      vkDestroySampler(logical_device_, texture_sampler_, nullptr);

    if (uniform_pool_ != VK_NULL_HANDLE)
      vkDestroyDescriptorPool(logical_device_, uniform_pool_, nullptr);

    DestroyBuffer(uniform_buffer_);

    if (uniform_set_layout_ != VK_NULL_HANDLE)
      vkDestroyDescriptorSetLayout(logical_device_, uniform_set_layout_,
                                   nullptr);

    if (image_available_signal_ != VK_NULL_HANDLE)
      vkDestroySemaphore(logical_device_, image_available_signal_, nullptr);

    if (render_finished_signal_ != VK_NULL_HANDLE)
      vkDestroySemaphore(logical_device_, render_finished_signal_, nullptr);

    if (still_rendering_fence_ != VK_NULL_HANDLE)
      vkDestroyFence(logical_device_, still_rendering_fence_, nullptr);

    if (command_pool_ != VK_NULL_HANDLE)
      vkDestroyCommandPool(logical_device_, command_pool_, nullptr);

    if (logical_device_ != VK_NULL_HANDLE)
      vkDestroyPipeline(logical_device_, pipeline_, nullptr);

    if (pipeline_layout_ != VK_NULL_HANDLE)
      vkDestroyPipelineLayout(logical_device_, pipeline_layout_, nullptr);

    if (render_pass_ != VK_NULL_HANDLE)
      vkDestroyRenderPass(logical_device_, render_pass_, nullptr);

    vkDestroyDevice(logical_device_, nullptr);
  }
  if (instance_ != VK_NULL_HANDLE) {
    if (surface_ != VK_NULL_HANDLE)
      vkDestroySurfaceKHR(instance_, surface_, nullptr);

    if (debug_messenger_ != VK_NULL_HANDLE)
      vkDestroyDebugUtilsMessengerEXT(instance_, debug_messenger_, nullptr);

    vkDestroyInstance(instance_, nullptr);
  }
}

void Graphics::InitializeVulkan() {
  CreateInstance();
  SetupDebugMessenger();
  CreateSurface();
  PickPhysicalDevice();
  CreateLogicalDeviceAndQueues();
  CreateSwapChain();
  CreateImageViews();
  CreateRenderPass();
  CreateDescriptorSetLayouts();
  CreateGraphicsPipeline();
  CreateFramebuffers();
  CreateCommandPool();
  CreateCommandBuffer();
  CreateSignals();
  CreateUniformBuffers();
  CreateDescriptorPools();
  CreateDescriptorSets();
  CreateTextureSampler();
}

}  // namespace veng
