#include <psemek/sdl2/init.hpp>
#include <psemek/log/log.hpp>
#include <psemek/util/exception.hpp>

#include <SDL2/SDL.h>

namespace psemek::sdl2
{

	namespace
	{

		struct sdl_initializer
		{
			sdl_initializer()
			{
				if (SDL_Init(0) != 0)
					fail("Failed to initialize SDL2: ");

				SDL_version version;
				SDL_GetVersion(&version);
				log::info() << "Initialized SDL " << (int)version.major << '.' << (int)version.minor << '.' << (int)version.patch;
			}

			~sdl_initializer()
			{
				SDL_Quit();
			}

			static std::shared_ptr<sdl_initializer> instance()
			{
				static std::weak_ptr<sdl_initializer> ptr;

				if (auto p = ptr.lock(); p)
					return p;

				auto p = std::make_shared<sdl_initializer>();
				ptr = p;
				return p;
			}
		};

		struct subsystem_initializer
		{
			std::shared_ptr<sdl_initializer> sdl_init;
			std::uint32_t subsystems;

			subsystem_initializer(std::uint32_t subsystems)
				: sdl_init(sdl_initializer::instance())
				, subsystems(subsystems)
			{
				if (SDL_InitSubSystem(subsystems) != 0)
					fail("Failed to initialize SDL2 subsystems: ");
			}

			~subsystem_initializer()
			{
				SDL_QuitSubSystem(subsystems);
			}
		};

	}

	[[noreturn]] void fail(std::string const & message)
	{
		throw util::exception(message + SDL_GetError());
	}

	std::shared_ptr<void> init(std::uint32_t subsystems)
	{
		return std::make_shared<subsystem_initializer>(subsystems);
	}

}
