/* GMM (C) 2018-2019 Stephane Charette <stephanecharette@gmail.com>
 * $Id: Log.cpp 2718 2019-02-07 07:08:42Z stephane $
 */

#include "Log.hpp"


CriticalSection logging_mutex;

std::string get_log_filename(void)
{
	#ifdef WIN32
	const std::string log_filename = File::getSpecialLocation(File::tempDirectory).getFullPathName().toStdString() + std::string("\\gmm.log");
	#else
	const std::string log_filename = "/var/log/gmm.log";
	#endif

	return log_filename;
}


std::ofstream &get_log_stream(void)
{
	static std::ofstream stream;

	if (stream.is_open() == false)
	{
		auto flags = std::ofstream::out | std::ofstream::app;

		bool file_truncated = false;
		const std::string filename = get_log_filename();

		// if the log file is getting too big, then truncate it
		File file(filename);
		const auto file_size	= file.getSize();
		const auto ten_MiB		= 10 * 1024 * 1024;

		if (file_size > ten_MiB)
		{
			flags = std::ofstream::out | std::ofstream::trunc;
			file_truncated = true;
		}

		stream.open(filename, flags);
		stream << std::endl << "-------------------------------------" << std::endl;
		if (file_truncated)
		{
			stream << "truncated previous log file (was " << Lox::Numbers::approximateSize(file_size) << ")" << std::endl;
		}
	}

	if (stream.good() == false)
	{
		throw Lox::Exception(LOX_WHERE, "failed to open output logging file \"" + get_log_filename() + "\"");
	}

	return stream;
}


std::string get_log_timestamp(void)
{
	const std::time_t now = std::time(nullptr);
	char buffer[50] = "";
	std::strftime(buffer, sizeof(buffer), "%a %Y-%m-%d %H:%M:%S", std::localtime(&now));

	return buffer;
}


Lox::Exception log_exception( const std::exception *e, const std::string &filename, const int line_number )
{
	Lox::Exception lox_exception;
	if (e == nullptr)
	{
		// not much we can get from a null exception pointer
		lox_exception = Lox::Exception( LOX_WHERE, "null exception" );
	}
	else if (dynamic_cast<const Lox::Exception*>(e) != nullptr)
	{
		// we already have a Lox exception!
		lox_exception = *dynamic_cast<const Lox::Exception*>(e);
	}
	else if (dynamic_cast<const std::exception*>(e) != nullptr)
	{
		// convert a normal exception to a Lox exception
		lox_exception = Lox::Exception( LOX_WHERE, *e );
	}
	else
	{
		lox_exception = Lox::Exception( LOX_WHERE, "unknown exception type" );
	}

	if (lox_exception.shouldDisplay)
	{
		LOG_MSG(lox_exception.to_string());
	}

	return lox_exception;
}


void log_and_show_exception( const std::exception *e, const std::string &filename, const int line_number )
{
	// problem detected -- display a window to the user

	const Lox::Exception lox_exception = log_exception(e, filename, line_number);

	if (lox_exception.shouldDisplay)
	{
		try
		{
			AlertWindow::showMessageBoxAsync(
				AlertWindow::WarningIcon,
				"GMM problem detected!",
				"An error or exception was detected.\r\n"
				"\r\n"
				"The file " + get_log_filename() + " may have some additional details on the cause of the error.\r\n"
				"\r\n"
				"Please try again, consult the log file, or contact Stephane Charette (stephanecharette@gmail.com) for assistance." );
		}
		catch (...)
		{
			// do nothing
		}
	}

	return;
}
