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

#include "fs_private.h"

enum {
    FS_MAX_DIR_HASH_SIZE = 1024,
};

void FS_AddNonPackFileDirectory_Internal(const char *base, const char *game, const char *path,
                  const char *extension)
{
    char gamePath[FS_OSPATH_SIZE];
    int namesLength;
    int fileCount;
    char **files;
    int hashSize;
    fs_dir_file_list_t *fileList;
    fs_dir_file_t **hashTable;
    fs_dir_file_t *entries;
    char *nameCursor;
    int index;
    char *name;
    uint32_t hash;
    char osPath[CODUO_FS_PACK_NAME_SIZE];

    sprintf(gamePath, "%s/%s", game, path);
    FS_BuildOSPath(base, gamePath, "", osPath);
    osPath[strlen(osPath) - 1] = '\0';

    files = Sys_ListFiles(osPath, extension, NULL, &fileCount, 0);

    namesLength = 0;
    for (index = 0; index < fileCount; index++) {
        namesLength += (int)strlen(files[index]) + 1;
    }

    hashSize = 1;
    while (hashSize <= FS_MAX_DIR_HASH_SIZE &&
           hashSize <= fileCount) {
        hashSize <<= 1;
    }

    fileList = Z_Malloc(sizeof(*fileList) +
                        (size_t)hashSize * sizeof(*hashTable));
    fileList->hashSize = hashSize;
    fileList->hashTable = (fs_dir_file_t **)(fileList + 1);
    hashTable = fileList->hashTable;

    for (index = 0; index < fileList->hashSize; index++) {
        hashTable[index] = NULL;
    }

    Q_strncpyz(fileList->path, path, CODUO_FS_PACK_NAME_SIZE);
    fileList->next = fs_dir_file_lists;
    fs_dir_file_lists = fileList;
    fileList->numFiles = fileCount;

    entries = Z_Malloc((size_t)fileCount * sizeof(*entries) +
                       (size_t)namesLength);
    nameCursor = (char *)(entries + fileCount);

    for (index = 0; index < fileCount; index++) {
        name = files[index];
        Q_strlwr(name);
        hash = FS_HashFileName(name, fileList->hashSize);

        entries[index].name = nameCursor;
        strcpy(entries[index].name, name);
        nameCursor += strlen(name) + 1;

        entries[index].next = hashTable[hash];
        entries[index].payload = NULL;
        entries[index].clearCallback = NULL;
        hashTable[hash] = &entries[index];
    }

    fileList->fileList = entries;

    Sys_FreeFileList(files);
    Sys_LoadingKeepAlive();
}
