#include "vvram.h"
#include "vram0.h"


bool SplitTarFName(char* tar_fname, char** dir, char** name) {
    u32 len = strnlen(tar_fname, 100 + 1);
    if (!len || (len == 101)) return false;

    // remove trailing slash
    if (tar_fname[len-1] == '/') tar_fname[--len] = '\0';

    // find last slash
    char* slash = strrchr(tar_fname, '/');

    // relative root dir entry
    if (!slash) {
        *name = tar_fname;
        *dir = NULL;
    } else {
        *slash = '\0';
        *name = slash + 1;
        *dir = tar_fname;
    }

    return true;
}


bool CheckVVramDrive(void) {
    return CheckVram0Tar();
}

bool ReadVVramDir(VirtualFile* vfile, VirtualDir* vdir) {
    vfile->name[0] = '\0';
    vfile->flags = VFLAG_READONLY;
    vfile->keyslot = 0xFF;


    // get current dir name
    char curr_dir[100 + 1];
    if (vdir->offset == (u64) -1) return false; // end of the dir?
    else if (!vdir->offset) *curr_dir = '\0'; // relative root?
    else {
        // vdir->offset is offset of dir entry + 0x200
        TarHeader* tar = (TarHeader*) OffsetVTarEntry(vdir->offset - 0x200);
        strncpy(curr_dir, tar->fname, 100);
        u32 len = strnlen(curr_dir, 100 + 1);
        if (len == 101) return false; // path error
        if (curr_dir[len-1] == '/') curr_dir[len-1] = '\0';
    }


    // using vdir index to signify the position limits us to 1TiB TARs
    void* tardata = NULL;
    if (vdir->index < 0) tardata = FirstVTarEntry();
    else tardata = NextVTarEntry(OffsetVTarEntry(vdir->index << 9));

    if (tardata) do {
        TarHeader* tar = (TarHeader*) tardata;
        char tar_fname[100 + 1];
        char *name, *dir;

        strncpy(tar_fname, tar->fname, 100);
        if (!SplitTarFName(tar_fname, &dir, &name)) return false;
        if ((!dir && !*curr_dir) || (dir && (strncmp(dir, curr_dir, 100) == 0))) break;
    } while ((tardata = NextVTarEntry(tardata)));

    // match found?
    if (tardata) {
        u64 fsize;
        bool is_dir;
        void* fdata = GetVTarFileInfo(tardata, NULL, &fsize, &is_dir);

        vfile->offset = (u32) fdata - VRAM0_OFFSET;
        vfile->size = fsize;
        if (is_dir) vfile->flags |= VFLAG_DIR;

        vdir->index = (vfile->offset >> 9) - 1;
    } else { // not found
        vdir->offset = (u64) -1;
        return false;
    }


    return true;
}

int ReadVVramFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) {
    if (vfile->flags & VFLAG_DIR) return -1;
    void* fdata = (u8*) VRAM0_OFFSET + vfile->offset;

    // range checks in virtual.c
    memcpy(buffer, (u8*) fdata + offset, count);
    return 0;
}

bool GetVVramFilename(char* name, const VirtualFile* vfile) {
    void* tardata = OffsetVTarEntry(vfile->offset - 0x200);
    TarHeader* tar = (TarHeader*) tardata;
    char tar_fname[100 + 1];
    char *name_tmp, *dir;

    strncpy(tar_fname, tar->fname, 100);
    if (!SplitTarFName(tar_fname, &dir, &name_tmp)) return false;
    strncpy(name, name_tmp, 100);

    return true;
}

bool MatchVVramFilename(const char* name, const VirtualFile* vfile) {
    void* tardata = OffsetVTarEntry(vfile->offset - 0x200);
    TarHeader* tar = (TarHeader*) tardata;
    char tar_fname[100 + 1];
    char *name_tmp, *dir;

    strncpy(tar_fname, tar->fname, 100);
    if (!SplitTarFName(tar_fname, &dir, &name_tmp)) return false;
    return (strncasecmp(name, name_tmp, 100) == 0);
}

u64 GetVVramDriveSize(void) {
    return VRAM0_LIMIT;
}
