#pragma once

#include <iostream>
#include <initializer_list>

enum LogType {
	DEBUG, INFO, LOAD, WARNING, ERROR
};

class Log { 
public:
	Log() = delete;
	template<typename T, typename... Args>
	Log(LogType a, T t, Args... args);
	static void setLogLevel(int lv);
private:;
	template <typename T>
	void print(bool cerr, T t);
	template<typename T, typename... Args>
	void print(bool cerr, T t, Args... args);
	static int level;
};

template<typename T, typename... Args>
Log::Log(LogType a, T t, Args... args)
{
	switch(a) {
	case LogType::DEBUG:
		if(level < 3)
			return;
		std::cout << "[DEBUG]   ";
		break;
	case LogType::INFO:
		if(level < 2)
			return;
		std::cout << "[INFO]    ";
		break;
	case LogType::LOAD:
		if(level < 2)
			return;
		std::cout << "[LOAD]    ";
		break;
	case LogType::WARNING:
		if(level < 3)
			return;
		std::cout << "[WARNING] ";
		break;
	case LogType::ERROR:
		if(level < 1)
			return;
		std::cerr << "[ERROR]   ";
		break;
	default:
		std::cout << "          ";
		break;
	}
	print(a == ERROR, t, args...);
	if(a == ERROR) {
		std::cerr << std::endl;
	}
	else {
		std::cout << std::endl;
	}
}

template <typename T>
void Log::print(bool cerr, T t)
{
	if(cerr) {
		std::cerr << t;
	}
	else {
		std::cout << t;
	}
}

template<typename T, typename... Args>
void Log::print(bool cerr, T t, Args... args)
{
	if(cerr) {
		std::cerr << t;
	}
	else {
		std::cout << t;
	}

    print(cerr, args...);
}