#include <iostream>
#include <chrono>
#include <ctime>
#include "Logger.hpp"

Logger::Levels Logger::loggingLevel = Levels::Info;
bool Logger::debugEnabled;

void Logger::Log(std::string message) {
	dispatchLog(Levels::Log, message, false);
}

void Logger::Info(std::string message) {
	dispatchLog(Levels::Info, message, true);
}

void Logger::Debug(std::string message) {
	dispatchLog(Levels::Info, message, true);
}

void Logger::Warn(std::string message) {
	dispatchLog(Levels::Warning, message, false);
}

void Logger::Error(std::string message) {
	dispatchLog(Levels::Error, message, false);
}

void Logger::SetMaxLoggingLevel(Levels level) {
	loggingLevel = level;
}

void Logger::SetDebugMode(bool enabled) {
	debugEnabled = enabled;
}

void Logger::dispatchLog(Levels severity, std::string message, bool isDebug) {
	if (!debugEnabled && isDebug)
		return;
	if (severity > loggingLevel || severity == loggingLevel) {
		switch (severity) {
		case Levels::All:
		case Levels::Log:
		case Levels::Info:
			log(getMessageType(severity, isDebug) + getTimestamp(), message);
			break;
		case Levels::Warning:
		case Levels::Error:
			logError(getMessageType(severity, isDebug) + getTimestamp(), message);
			break;
		}
	}
}

std::string Logger::getTimestamp() {
	char buffer[100];
	time_t t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
	struct tm * p = localtime(&t);
	strftime(buffer, 100, "%a, %F, %H:%M:%S", p);
	return buffer;
}

std::string Logger::getMessageType(Levels severity, bool debug) {
	std::string messageType = " | ";
	switch (severity) {
	case Levels::All:
	case Levels::Info:
		messageType += debug?"DBUG":"INFO";
		break;
	case Levels::Warning:
		messageType += "WARN";
		break;
	case Levels::Error:
		messageType += "ERR!";
		break;
	default:
		break;
	}
	return messageType + " | ";
}

void Logger::log(std::string head, std::string message) {
	std::clog << head << ": " << message << std::endl;
}

void Logger::logError(std::string head, std::string message) {
	std::clog.flush();
	std::cerr << head << ": " << message << std::endl;
}