#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include <luna/PathParser.h>

Result<u64> sys_chdir(Registers*, SyscallArgs args)
{
    auto path = TRY(MemoryManager::strdup_from_user(args[0]));

    Thread* current = Scheduler::current();

    if (PathParser::is_absolute(path.view()))
    {
        SharedPtr<VFS::Inode> inode = TRY(VFS::resolve_path(path.chars(), current->auth));

        if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
        if (!VFS::can_execute(inode, current->auth)) return err(EACCES);

        inode->add_handle();
        if (current->current_directory) current->current_directory->remove_handle();

        current->current_directory = inode;
        current->current_directory_path = move(path);

        return 0;
    }
    else
    {
        SharedPtr<VFS::Inode> inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));

        if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
        if (!VFS::can_execute(inode, current->auth)) return err(EACCES);

        auto old_wdir = current->current_directory_path.view();

        String new_path = TRY(PathParser::join(old_wdir.is_empty() ? "/"_sv : old_wdir, path.view()));

        inode->add_handle();
        if (current->current_directory) current->current_directory->remove_handle();

        current->current_directory = inode;
        current->current_directory_path = move(new_path);

        return 0;
    }
}

Result<u64> sys_getcwd(Registers*, SyscallArgs args)
{
    u8* buf = (u8*)args[0];
    usize size = (usize)args[1];

    Thread* current = Scheduler::current();

    StringView cwd = current->current_directory_path.view();
    if (cwd.is_empty()) cwd = "/"_sv;

    usize cwd_size = cwd.length() + 1;

    if (cwd_size > size) return cwd_size;

    if (!MemoryManager::copy_to_user(buf, cwd.chars(), cwd_size)) return err(EFAULT);

    return cwd_size;
}