#pragma once

#include "syscall.hxx"

extern char ExecutiveLogStringBuffer[4096];

/**
 * Write formatted data to the executive log buffer with ExecutiveLogFormatOptions
 *
 * \param Value     Value to format
 * \param BufferPos Position in ExecutiveLogStringBuffer
 * \param Args      Specification
 */
template<class _Type>
inline void ExecutiveLogFormatValue(const _Type* Value, int& BufferPos, const char* Args) = delete;

/**
 * Type has a format function
 */
template<class _Type>
concept ExecutiveLogCanFormat = requires(const _Type* Value, int& BufferPos, const char* Args) {
	ExecutiveLogFormatValue(Value, BufferPos, Args);
};


/**
 * Log something.
 *
 * Format strings use \{\} for substitutions, substitutions can contain a number that
 * updates the substitution index and a 127 byte format specification for formatters
 */
template<ExecutiveLogCanFormat... _Type>
inline void ExecutiveLog(const char* Format, const _Type&... Items) {
	// Format items and other goodies
	const void* FormatItems[sizeof...(_Type)] = { &Items... };
	void (*FormatFunctions[sizeof...(_Type)])(const void*, int&, const char*) = {
		// !!! VERY UNSAFE STUPID DUMB PIECE OF SHIT HACK !!!
		reinterpret_cast<void (*)(const void*, int&, const char*)>(static_cast<void (*)(const _Type*, int&, const char*)>(ExecutiveLogFormatValue))...
	};
	
	// Buffer for format spec
	char FormatOptions[128] = {};
	
	// Indicies
	int bpos = 0;
	int fpos = 0;
	int apos = 0;
	
	// Fill out the log buffer
	while (Format[fpos] != 0 && bpos < 4095) {
		// Handle replacements
		if (Format[fpos] == '{') {
			// Clear format options
			FormatOptions[0] = 0;

			// Pattern matching cant come soon enough
			switch (Format[++fpos]) {
				case 0: { // Me when the uh i uh
					LnxWrite(1, "BAD FORMAT STRING: ", 19);
					LnxWrite(1, Format, fpos);
					LnxWrite(1, "\n", 1);
					return;
				}
				case '{': { // Escape
					ExecutiveLogStringBuffer[bpos++] = '{';
					fpos += 1;
					break;
				}
				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
				case '8':
				case '9': {
					volatile auto a = *(char*)(nullptr);
				}
				case ':':
				default: {
					volatile auto a = *(char*)(nullptr);
				}
				case '}': { // Finish the thing
					fpos += 1;
					// TODO: unsafe
					FormatFunctions[apos](FormatItems[apos], bpos, FormatOptions);
					apos += 1;
				}
			}
		} else {
			ExecutiveLogStringBuffer[bpos++] = Format[fpos++];
		}
	}

	// Add our newline.
	ExecutiveLogStringBuffer[bpos++] = '\n';

	// Write to stdout.
	LnxWrite(1, ExecutiveLogStringBuffer, bpos);
}

// Formatters for builtin types
template<>
inline void ExecutiveLogFormatValue<long>(const long* Value, int& BufferPos, const char* Args) {
	// We only work with absolutes here.
	long Absolute = *Value < 0 ? -*Value : *Value;
	
	// Find the biggest thing i dont fucking know i hate code comments
	long TheBiggest = 1;
	while (TheBiggest <= Absolute) TheBiggest *= 10;

	// Sign
	if (*Value < 0 && BufferPos < 4095) ExecutiveLogStringBuffer[BufferPos++] = '-';

	// The number
	while (Absolute != 0 && BufferPos < 4095) {
		ExecutiveLogStringBuffer[BufferPos++] = '0' + static_cast<char>(Absolute * 10 / TheBiggest);
		Absolute %= TheBiggest / 10;
		TheBiggest /= 10;
	}

	return;
}

template<>
inline void ExecutiveLogFormatValue<int>(const int* Value, int& BufferPos, const char* Args) {
	long LongValue = *Value;
	ExecutiveLogFormatValue(&LongValue, BufferPos, Args);
	return;
}