#ifndef POLYGUN_UTILS_LOGGER_HPP
#define POLYGUN_UTILS_LOGGER_HPP

#include <cstdio>
#include <cstdarg>

namespace polygun::utils {
	class Logger final {
	public:
		Logger(bool output_to_file, bool enable_verbose);
		~Logger();

		void info(const char* file, size_t line, const char* fmt, ...);
		void warning(const char* file, size_t line, const char* fmt, ...);
		void error(const char* file, size_t line, const char* fmt, ...);
		void fatal(const char* file, size_t line, const char* fmt, ...);
		void verbose(const char* file, size_t line, const char* fmt, ...);

		static Logger& get() { return *s_instance; }
		static void create(bool output_to_file, bool enable_verbose);
		static void cleanup() { delete s_instance; }

	private:
		bool m_output_to_file, m_enable_verbose;
		FILE* m_output_file;
		static Logger* s_instance;

	private:
		void print_internal(FILE* output, const char* mode, const char* file, size_t line, const char* fmt, va_list args);
	};
}

#define LOG_INFO(fmt, ...) polygun::utils::Logger::get().info(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define LOG_WARNING(fmt, ...) polygun::utils::Logger::get().warning(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define LOG_ERROR(fmt, ...) polygun::utils::Logger::get().error(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define LOG_FATAL(fmt, ...) polygun::utils::Logger::get().fatal(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define LOG_VERBOSE(fmt, ...) polygun::utils::Logger::get().verbose(__FILE__, __LINE__, fmt, ##__VA_ARGS__)

#endif // POLYGUN_UTILS_LOGGER_HPP
