#pragma once
#include <luna/Result.h>

#ifdef ARCH_X86_64
#include "arch/x86_64/MMU.h"
#else
#error "Unknown architecture."
#endif

constexpr u64 PAGES_PER_HUGE_PAGE = ARCH_HUGE_PAGE_SIZE / ARCH_PAGE_SIZE;

namespace MMU
{
    enum Flags
    {
        None = 0,
        ReadWrite = 1,
        User = 2,
        NoExecute = 4,
        WriteThrough = 8,
        CacheDisable = 16,
    };

    enum class UseHugePages
    {
        No = 0,
        Yes = 1
    };

    u64 translate_physical_address(u64 phys);

    void switch_page_directory(PageDirectory* dir);
    PageDirectory* get_page_directory();

    Result<void> map(u64 virt, u64 phys, int flags, UseHugePages use_huge_pages, PageDirectory* directory = nullptr);
    Result<u64> unmap(u64 virt, PageDirectory* directory = nullptr);
    Result<u64> get_physical(u64 virt, PageDirectory* directory = nullptr);
    Result<int> get_flags(u64 virt, PageDirectory* directory = nullptr);
    Result<void> remap(u64 virt, int flags);

    void flush_all();

    Result<PageDirectory*> create_page_directory_for_userspace();
    Result<void> delete_userspace_page_directory(PageDirectory* directory);
    Result<PageDirectory*> clone_userspace_page_directory(PageDirectory* directory);
    void setup_initial_page_directory();

    PageDirectory* kernel_page_directory();
}