// fat12.c

#include "fat12.h"
#include "disk_io.h"
#include "print.h"
#include "strings.h"

#include "fat12.h"
#include "disk_io.h"  // Assuming this contains `disk_read` for sector-level disk access

#define SECTOR_SIZE 512
#define FAT12_CLUSTER_SIZE 1  // Usually 1 sector per cluster for FAT12
#define FAT12_EOC 0xFF8  // End of cluster chain marker in FAT12

// Function to convert a cluster number to an LBA (Logical Block Address)
static uint32_t cluster_to_lba(uint16_t cluster, const fat12_boot_sector_t *boot_sector) {
    uint32_t first_data_sector = boot_sector->reserved_sectors + 
                                 (boot_sector->num_fats * boot_sector->fat_size_16) + 
                                 boot_sector->root_entry_count * 32 / SECTOR_SIZE;
    return first_data_sector + (cluster - 2) * boot_sector->sectors_per_cluster;
}

// Function to read the FAT to find the next cluster
static uint16_t fat12_get_next_cluster(uint16_t cluster, const fat12_boot_sector_t *boot_sector) {
    uint32_t fat_offset = cluster + (cluster / 2);  // FAT12 uses 12-bit entries
    uint16_t next_cluster;
    uint8_t fat_entry[2];

    // Read the FAT sector where the current cluster is stored
    uint32_t fat_sector = boot_sector->reserved_sectors + fat_offset / SECTOR_SIZE;
    uint32_t fat_offset_in_sector = fat_offset % SECTOR_SIZE;

    disk_read(fat_sector, fat_entry, sizeof(fat_entry));

    if (cluster & 1) {
        next_cluster = ((fat_entry[1] << 4) | (fat_entry[0] >> 4)) & 0xFFF;  // Odd cluster number
    } else {
        next_cluster = ((fat_entry[1] << 8) | fat_entry[0]) & 0xFFF;  // Even cluster number
    }

    return next_cluster;
}

int fat12_read_file(fat12_dir_entry_t *entry, void *buffer) {
    fat12_boot_sector_t boot_sector;
    uint16_t current_cluster = entry->first_cluster_low;
    uint32_t file_size = entry->file_size;
    uint8_t *buf_ptr = (uint8_t *)buffer;
    uint32_t bytes_read = 0;

    // Load the boot sector (this would need to be done once in initialization, but for simplicity here)
    disk_read(0, &boot_sector, sizeof(fat12_boot_sector_t));

    // Read each cluster of the file
    while (current_cluster < FAT12_EOC && bytes_read < file_size) {
        // Calculate the LBA of the current cluster
        uint32_t lba = cluster_to_lba(current_cluster, &boot_sector);

        // Read the cluster (sector) into the buffer
        disk_read(lba, buf_ptr, SECTOR_SIZE);

        buf_ptr += SECTOR_SIZE;
        bytes_read += SECTOR_SIZE;

        // Get the next cluster in the FAT chain
        current_cluster = fat12_get_next_cluster(current_cluster, &boot_sector);
    }

    // Ensure we don’t read beyond the file size
    if (bytes_read > file_size) {
        bytes_read = file_size;
    }

    return bytes_read;  // Return the number of bytes read
}





static fat12_boot_sector_t boot_sector;
static fat12_dir_entry_t root_directory[ROOT_DIR_ENTRIES];

// FAT12 Initialization (called during filesystem mount)
int fat12_init(void) {
    // Read boot sector
    if (disk_read(0, &boot_sector, sizeof(fat12_boot_sector_t)) != 0) {
        printf("Failed to read boot sector\n");
        return -1;
    }

    // Check for FAT12 signature
    if (*(uint16_t *)((char *)&boot_sector + 510) != FAT12_SIGNATURE) {
        printf("Invalid FAT12 filesystem\n");
        return -1;
    }
    
    printf("FAT12 filesystem successfully mounted\n");
    return 0;
}

// Reads the root directory
int fat12_read_root_directory(void) {
    uint32_t root_dir_lba = (boot_sector.reserved_sectors + boot_sector.num_fats * boot_sector.fat_size_16) * boot_sector.bytes_per_sector;
    
    if (disk_read(root_dir_lba, root_directory, sizeof(root_directory)) != 0) {
        printf("Failed to read root directory\n");
        return -1;
    }

    printf("Root directory loaded\n");
    return 0;
}

// Find a file by name in the root directory
int fat12_find_file(const char *filename, fat12_dir_entry_t *entry) {
    for (int i = 0; i < ROOT_DIR_ENTRIES; i++) {
        if (strncmp(root_directory[i].filename, filename, 8) == 0) {
            *entry = root_directory[i];
            return 1;
        }
    }
    
    printf("File not found\n");
    return 0;
}



