#pragma once
#include <array>
#include <limits>
#include <string>
#include <vector>
#include "kernel_types.hpp"
#include "helpers.hpp"
#include "memory.hpp"

class Kernel {
	std::array<u32, 16>& regs;
	Memory& mem;

	// The handle number for the next kernel object to be created
	u32 handleCounter;
	std::vector<KernelObject> objects;

	u32 currentProcess;

	// Get pointer to the object with the specified handle
	KernelObject* getObject(u32 handle) {
		// Accessing an object that has not been created
		if (handle >= objects.size()) [[unlikely]] {
			return nullptr;
		}

		return &objects[handle];
	}

	// Get pointer to the object with the specified handle and type
	KernelObject* getObject(u32 handle, KernelObjectType type) {
		if (handle >= objects.size() || objects[handle].type != type) [[unlikely]] {
			return nullptr;
		}

		return &objects[handle];
	}

	Handle makeObject(KernelObjectType type) {
		if (handleCounter == std::numeric_limits<Handle>::max()) [[unlikely]] {
			Helpers::panic("Hlep we somehow created enough kernel objects to overflow this thing");
		}

		objects.push_back(KernelObject(handleCounter, type));
		printf("Created %s object with handle %d\n", kernelObjectTypeToString(type), handleCounter);
		return handleCounter++;
	}

	Handle makeProcess();
	KernelObject* getProcessFromPID(Handle handle);

	void createAddressArbiter();
	void getResourceLimit();
	void getResourceLimitLimitValues();
	std::string getProcessName(u32 pid);

public:
	Kernel(std::array<u32, 16>& regs, Memory& mem) : regs(regs), mem(mem), handleCounter(0) {
		objects.reserve(512); // Make room for a few objects to avoid further memory allocs later
	}
	void serviceSVC(u32 svc);
	void reset();
};