// libporffor-init.c
// Initialization and accessor functions for Porffor library
// These must be in a separate file since libporffor.c is auto-generated

#include <stdlib.h>
#include <stdint.h>
#include <string.h>

// External reference to _memory from libporffor.c
extern char *_memory;
extern uint32_t _memoryPages;

// External string initialization function (from libporffor.c)
extern void _main(void);

// External allocator state from libporffor.c
extern int32_t jjporfjjcurrentPtr;
extern int32_t jjporfjjendPtr;

// Minimum required pages (13 pages = 832KB, Porffor's default)
#define MIN_PAGES 13
// Minimum reserved bytes for Lua parameters (1KB minimum)
#define MIN_RESERVED 1024

// Initialize Porffor runtime with configurable memory size
// pageCount: Number of 64KB pages to allocate (default: 256 = 16MB)
// porfforStart: Where Porffor allocator starts (0=old way, reservedBytes=new way)
// reservedBytes: Bytes to reserve for Lua parameters (default: 1000000 = 1MB)
// For big datasets: 1024 pages = 64MB, 4096 pages = 256MB
// Returns: 0 on success, -1 on failure (invalid params, too few pages, or alloc failed)
int porfforInit(int pageCount, int porfforStart, int reservedBytes)
{
	int totalSize = pageCount * 65536;
	// Validate minimum page count
	if (pageCount < MIN_PAGES)
	{
		return -1;
	}
	// Validate parameters
	if (porfforStart < 0 || porfforStart >= totalSize)
	{
		return -1;
	}
	if (reservedBytes < MIN_RESERVED || reservedBytes > totalSize)
	{
		return -1;
	}
	// Allocate memory for Porffor runtime
	// Page size is 65536 bytes (64KB)
	_memory = (char *)calloc(pageCount, 65536);
	if (_memory == NULL)
	{
		return -1;
	}
	// Update Porffor's page count to match actual allocation
	_memoryPages = pageCount;
	// Initialize allocator state - Porffor starts at porfforStart
	jjporfjjcurrentPtr = porfforStart;
	jjporfjjendPtr = totalSize;
	_main(); // Initialize string literals in memory
	return 0;
}

// Get pointer to memory buffer
char *porfforGetMemory()
{
	return _memory;
}

// Get current allocator position (for debugging)
int porfforGetCurrentPtr()
{
	return jjporfjjcurrentPtr;
}

// Get the end of reserved zone (for validation)
int porfforGetReservedEnd(int reservedBytes)
{
	return reservedBytes;
}

// Write test data to external buffer provided by Lua
// This allows returning large data without relying on Porffor's runtime initialization
void porfforWriteData(uint8_t *buffer, int bufferSize)
{
	if (buffer == NULL || bufferSize <= 0)
	{
		return;
	}
	// Write sequential data pattern: 0, 1, 2, 3, ...
	for (int i = 0; i < bufferSize; i++)
	{
		buffer[i] = (uint8_t)(i & 0xFF);
	}
}

// Write specific pattern to external buffer
void porfforWritePattern(uint8_t *buffer, int bufferSize, uint8_t startValue, uint8_t step)
{
	if (buffer == NULL || bufferSize <= 0)
	{
		return;
	}
	for (int i = 0; i < bufferSize; i++)
	{
		buffer[i] = startValue + (i * step);
	}
}

// Write computed data using external function pointer
// The computeFunc is called for each index to get the value
typedef uint8_t (*ComputeFunc)(int index);
void porfforWriteComputed(uint8_t *buffer, int bufferSize, ComputeFunc computeFunc)
{
	if (buffer == NULL || bufferSize <= 0 || computeFunc == NULL)
	{
		return;
	}
	for (int i = 0; i < bufferSize; i++)
	{
		buffer[i] = computeFunc(i);
	}
}
