#include "DataLogger.h"

#include "utils.h"

#include <Preferences.h>

#include <limits>

DataLogger DataLogger::mainLogger;

DataLogger::DataLogger()
{
}

DataLogger::~DataLogger()
{
}

void DataLogger::open()
{
	if(isOpen()) return;

	lastLogTime = -std::numeric_limits<float>::max();
	currentTime = 0.0f;

	Preferences preferences;
	preferences.begin("vm-log", false);
	uint16_t logFileIndex = preferences.getUShort("next", 1);
	preferences.putUShort("next", logFileIndex + 1);
	preferences.end();

	// clear existing files until we have enough free space
	{
		const unsigned long requiredSpace = 300000; // in bytes
		unsigned long totalSpace = SPIFFS.totalBytes();
		auto logFolder = SPIFFS.open("/log");
		auto oldFile = logFolder.openNextFile();
		while(oldFile && SPIFFS.usedBytes() + requiredSpace > totalSpace)
		{
			Serial.print("Deleting old log file: ");
			Serial.println(oldFile.name());

			SPIFFS.remove(oldFile.name());
			oldFile = logFolder.openNextFile();
		}
	}

	char fileName[32];
	sprintf(fileName, "/log/L%05d.csv", logFileIndex);

	file = SPIFFS.open(fileName, FILE_WRITE);
	if(!isOpen()) Serial.println("DataLogger: failed to open file");

	if(!file.print("time,speed,battery voltage,battery output current,temperature,altitude\n")) Serial.println("DataLogger: failed to write to file");
}

void DataLogger::close()
{
	if(!isOpen()) return;
	file.close();
}

void DataLogger::log(unsigned long timeMilliseconds, const Entry& entry)
{
	if(lastLogTime == -std::numeric_limits<float>::max()) lastTimeMilliseconds = timeMilliseconds;
	currentTime += (float)utils::elapsed(lastTimeMilliseconds, timeMilliseconds) / 1000.0f;
	lastTimeMilliseconds = timeMilliseconds;

	if((lastEntry.isDifferent(entry) || currentTime >= lastLogTime + 20.0f) && currentTime >= lastLogTime + 0.2f)
	{
		char line[128];
		sprintf(line, "%.3f,%.3f,%.3f,%.3f,%.1f,%.1f\n", currentTime, entry.speed, entry.batteryVoltage, entry.batteryOutputCurrent, entry.temperature, entry.altitude);
		file.print(line);

		if(currentTime >= lastFlushTime + 10.0f)
		{
			// we need to flush often enough, because the system is typically powered off right after arrival to destination
			file.flush();
			lastFlushTime = currentTime;
		}

		lastEntry = entry;
		lastLogTime = currentTime;
	}
}

bool DataLogger::isOpen()
{
	return file;
}

const char* DataLogger::currentLogFileName()
{
	return isOpen() ? file.name() : "";
}
