/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#include "DeviceManager.hpp"
#include "Device.hpp"
#include <stdexcept>
#include <sstream>

namespace OpenVulkano::Vulkan
{
	void DeviceManager::Init(const vk::Instance& instance)
	{
		if (!devices.empty()) Close();
		for (auto& physicalDevice: instance.enumeratePhysicalDevices())
		{
			devices.push_back(std::make_shared<Device>(physicalDevice));
		}
	}

	std::shared_ptr<Device> DeviceManager::GetCompatibleDevice(const vk::ArrayProxy<const std::string>& deviceExtensions)
	{
		for (const auto& device: devices)
		{
			if (device->IsExtensionAvailable(deviceExtensions)) return device;
		}
		throw std::runtime_error("No device with required extensions found!\n" + ProduceMissingDeviceCompatibilityReport(deviceExtensions));
	}

	std::string DeviceManager::ProduceMissingDeviceCompatibilityReport(const vk::ArrayProxy<const std::string>& deviceExtensions)
	{
		std::stringstream ss;
		ss << "Requested Extensions: [";
		bool first = true;
		for (const std::string& ext : deviceExtensions)
		{
			ss << ' ' << ext;
			if (first) first = false;
			else ss << ',';
		}
		ss << " ]\nAvailable Devices: [\n";
		for (const auto& device: devices)
		{
			ss << '\t' << device->GetDeviceName() << ": [";
			first = true;
			for (const std::string& ext : device->GetExtensions())
			{
				ss << ' ' << ext;
				if (first) first = false;
				else ss << ',';
			}
			ss << " ]\n";
		}
		ss << ']';
		return ss.str();
	}
}