#include "sys_log.h"
#include "system.h"
#include "platform.h"
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>

static int yrLog_init(void* loadtoken);
static int yrLog_tick(void) { return 0; }
static int yrLog_save(void* savetoken, void* saveevent, int* savefailed) { yrEvent_set(saveevent, 1); return 0; }
static int yrLog_canfreeze(void) { return 1; }
static int yrLog_freeze(void) {return 0;}
static int yrLog_unfreeze(void) {return 0;}
static int yrLog_shutdown(void);

static void yrLog_write(const char* file, int line, const char* function, const char* message);
static void yrLog_show(uint32_t color, uint64_t duration, const char* message);

static int		log_level = -1;
static FILE*	log_file = NULL; //the logger doesn't use yrFile because yrFile logs and doesn't have fprintf
static yrLock	logmsg_lock = NULL;
static char		logmsg_msg[512] = {0};
static uint64_t	logmsg_end = 0;
static uint32_t	logmsg_color = 0;

void yrLog_reg(void)
{
	yrSystem_register(sysLog,
					  yrLog_init,
					  yrLog_tick,
					  yrLog_save,
					  yrLog_canfreeze,
					  yrLog_freeze,
					  yrLog_unfreeze,
					  yrLog_shutdown,
					  0);
}

/****************************************
* System functions (init, tick, shutdown)
*****************************************/
static int yrLog_init(void* loadtoken)
{
	log_file = fopen("14c.log", "a");
	log_level = 1; //TODO: get this from startup params somewhere
	logmsg_lock = yrLock_create();
	logmsg_end = 0;
	if(!logmsg_lock) return -1;

	yrLog(0, "+++Program started+++");
	return 0;
}

static int yrLog_shutdown(void)
{
	if(logmsg_lock) yrLog(0, "---Program ended---");
	log_level = -1; //don't log anything if logging is not enabled
	if(log_file) {
		fprintf(log_file, "\n\n");
		fclose(log_file);
	}
	log_file = NULL;
	yrLock_destroy(logmsg_lock);
	logmsg_msg[0] = 0;
	return 0;
}

/********
* Logging
*********/
void _yrLogInternal(int level, uint32_t color, uint64_t duration, const char* file, int line, const char* function, const char* format, ...)
{
	if(level > abs(log_level)) return;

	//determine length and acquire buffer
	va_list args;
	va_start(args, format);
	int msglen = _vscprintf(format, args);
	char stackbuf[256];
	char* buf = NULL;
	if(msglen + 1 > sizeof(stackbuf)) {
		buf = malloc(msglen + 1);
	}
	if(!buf) {
		buf = stackbuf;
		msglen = sizeof(stackbuf) - 1;
	}

	//write message
	vsnprintf(buf, msglen + 1, format, args);

	//output message
	if(log_level >= 0) {
		yrLog_write(file, line, function, buf);
		yrLog_show(color, duration, buf);
	} else {
		//force log
		printf("%s\n", buf);
		FILE* flog = fopen("14c.log", "a");
		if(flog) {
			fprintf(flog, "%s\n", buf);
			fclose(flog);
		}
	}

	//cleanup
	if(buf != stackbuf) free(buf);
	va_end(args);
}

static void yrLog_write(const char* file, int line, const char* function, const char* message)
{
	//print timestamp
	unsigned year, month, day, hour, minute, second, milli;
	yr_get_real_time(&year, &month, &day, &hour, &minute, &second, &milli);
	fprintf(log_file, "[%4u/%2u/%2u-%2u:%02u:%02u.%03u]", year, month, day, hour, minute, second, milli);

	//print filestamp
	fprintf(log_file, "[%s:%i#%s]\t", file, line, function);

	//print message
	fprintf(log_file, "%s\n", message);

	fflush(log_file);
}

static void yrLog_show(uint32_t color, uint64_t duration, const char* message)
{
	if(duration == 0) return;
	yrLock_aqcuire(logmsg_lock);

	logmsg_color = color;
	logmsg_end = yr_get_microtime() + duration;
	strncpy(logmsg_msg, message, sizeof(logmsg_msg) - 1);
	//TODO: tell renderer to render this
	//TODO: do we actually need to keep the message if renderer already has it?
	//TODO: msgbox if renderer unavailable, or at least tell the user to check the log on shutdown

	yrLock_release(logmsg_lock);
}