/*
 * Copyright (c) 2018 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

#include "sd_card.h"

#include <zephyr.h>
#include <device.h>
#include <storage/disk_access.h>
#include <fs/fs.h>
#include <ff.h>
#include <string.h>
// #include <drivers/gpio.h>
// #include <devicetree.h>
#include <logging/log.h>

// LOG_MODULE_REGISTER(sd_card, CONFIG_LOG_SD_CARD_LEVEL);
#define CONFIG_FS_FATFS_MAX_LFN 255 //maximum filename length
#define MAX_FILE_LENGTH 1024 //1024 bits maximum file size

#define SD_ROOT_PATH "/SD:/"
#define PATH_MAX_LEN 260 /* Maximum length for path support by Windows file system*/

static const char *sd_root_path = "/SD:";
static FATFS fat_fs;
static bool sd_init_success;

static struct fs_mount_t mnt_pt = {
	.type = FS_FATFS,
	.fs_data = &fat_fs,
};

int sd_card_list_files(char *path)
{
	int ret;
	struct fs_dir_t dirp;
	static struct fs_dirent entry;
	// char abs_path_name[PATH_MAX_LEN + 1] = SD_ROOT_PATH;

	fs_dir_t_init(&dirp);
	
	if (!sd_init_success) {
		return -ENODEV;
	}

	if (path == NULL) {
		ret = fs_opendir(&dirp, sd_root_path);
		if (ret) {
			printk("Open SD card root dir failed\n");
			return ret;
		}
	} else {
		if (strlen(path) > CONFIG_FS_FATFS_MAX_LFN) {
			printk("Path is too long\n");
			return -FR_INVALID_NAME;
		}

		// strcat(abs_path_name, path); //appending path to root path
		
		ret = fs_opendir(&dirp, path);
		if (ret) {
			printk("Open assigned path failed\n");
			return ret;
		}
	}
	while (true) {
		ret = fs_readdir(&dirp, &entry);
		if (ret) {
			return ret;
		}

		if (entry.name[0] == 0) {
			break;
		}

		if (entry.type == FS_DIR_ENTRY_DIR) {
			printk("[DIR ] %s", entry.name);
		} else {
			printk("[FILE] %s", entry.name);
		}
	}

	ret = fs_closedir(&dirp);
	if (ret) {
		printk("Close SD card root dir failed\n");
		return ret;
	}

	return 0;
}

int sd_card_write(char const *const filename, char const *const data, size_t *size)
{
	struct fs_file_t f_entry;
	char abs_path_name[PATH_MAX_LEN + 1] = SD_ROOT_PATH;
	int ret;

	if (!sd_init_success) {
		return -ENODEV;
	}

	if (strlen(filename) > CONFIG_FS_FATFS_MAX_LFN) {
		printk("Filename is too long\n");
		return -FR_INVALID_NAME;
	}

	strcat(abs_path_name, filename);

	ret = fs_open(&f_entry, abs_path_name, FS_O_CREATE | FS_O_WRITE | FS_O_APPEND);
	if (ret) {
		printk("Create file failed\n");
		return ret;
	}

	/* If the file exists, moves the file position pointer to the end of the file */
	ret = fs_seek(&f_entry, 0, FS_SEEK_END);
	if (ret) {
		printk("Seek file pointer failed\n");
		return ret;
	}

	ret = fs_write(&f_entry, data, *size);
	if (ret < 0) {
		printk("Write file failed\n");
		return ret;
	}

	*size = ret;

	ret = fs_close(&f_entry);
	if (ret) {
		printk("Close file failed\n");
		return ret;
	}

	return 0;
}

int sd_card_read(char const *const filename, char *const data, size_t *size)
{
	struct fs_file_t f_entry;
	char abs_path_name[PATH_MAX_LEN + 1] = SD_ROOT_PATH;
	int ret;

	if (!sd_init_success) {
		return -ENODEV;
	}

	if (strlen(filename) > MAX_FILE_LENGTH) {
		printk("Filename is too long\n");
		return -FR_INVALID_NAME;
	}

	strcat(abs_path_name, filename);

	ret = fs_open(&f_entry, abs_path_name, FS_O_READ);
	if (ret) {
		printk("Open file failed\n");
		return ret;
	}

	ret = fs_read(&f_entry, data, *size);
	if (ret < 0) {
		printk("Read file failed\n");
		return ret;
	}

	*size = ret;
	if (*size == 0) {
		printk("File is empty\n");
	}

	ret = fs_close(&f_entry);
	if (ret) {
		printk("Close file failed\n");
		return ret;
	}

	return 0;
}

int sd_card_init(void)
{
	int ret;
	static const char *sd_dev = "SD";
	uint64_t sd_card_size_bytes;
	uint32_t sector_count;
	size_t sector_size;

	ret = disk_access_init(sd_dev);
	if (ret) {
		printk("SD card init failed, please check if SD card inserted\n");
		return -ENODEV;
	}

	ret = disk_access_ioctl(sd_dev, DISK_IOCTL_GET_SECTOR_COUNT, &sector_count);
	if (ret) {
		printk("Unable to get sector count\n");
		return ret;
	}
	printk("Sector count: %d", sector_count);

	ret = disk_access_ioctl(sd_dev, DISK_IOCTL_GET_SECTOR_SIZE, &sector_size);
	if (ret) {
		printk("Unable to get sector size\n");
		return ret;
	}
	printk("Sector size: %d bytes\n", sector_size);

	sd_card_size_bytes = (uint64_t)sector_count * sector_size;
	printk("SD card volume size: %d MB\n", (uint32_t)(sd_card_size_bytes >> 20));

	mnt_pt.mnt_point = sd_root_path;
	ret = fs_mount(&mnt_pt);
	if (ret) {
		printk("Mnt. disk failed, could be format issue. should be FAT/exFAT\n");
		return ret;
	}

	sd_init_success = true;

	return 0;
}