// ==========================================================================
// file.c
// (c) 2020, Aurel Dumitru
//
// Description:
// File operations
// =========================================================================

#include <string.h>
#include "file.h"
#include "fatfs.h"
#include "utils.h"
#include "devstatus.h"
#include "calibrations.h"

// FATFS data
FATFS	File_SDFatFS;
uint8_t	File_RWAllowed;
FIL		File_FileId, File_FileNwmId, File_FileFtpId;
char    File_Buffer[32*1024];


void File_Init(void)
{
	MX_FATFS_Init();
	HAL_Delay(10);
	File_RWAllowed = 0;
	DevStatus[DEVSTATUS_MICROSD_STATUS_IDX] = DEVSTATUS_MICROSD_FAIL;
	if (f_mount(&File_SDFatFS, SDPath, 1) == FR_OK)
	{
		if (File_SDFatFS.fs_type != FS_FAT32)
		{
			(void)HAL_IWDG_Refresh(&hiwdg1);
			if (f_mkfs("0:", FM_FAT32, 4096, File_Buffer, sizeof(File_Buffer)) != FR_OK)
				return;
			f_mount(NULL, (TCHAR const*)SDPath, 1);
			if (f_mount(&File_SDFatFS, SDPath, 1) != FR_OK)
				return;
		}
		File_RWAllowed = 1;
		DevStatus[DEVSTATUS_MICROSD_STATUS_IDX] = DEVSTATUS_MICROSD_OK;
	}
	else
	{
		if (f_mkfs("0:", FM_FAT32, 4096, File_Buffer, sizeof(File_Buffer)) != FR_OK)	return;
		if (f_mount(&File_SDFatFS, SDPath, 1) != FR_OK)									return;
		File_RWAllowed = 1;
		DevStatus[DEVSTATUS_MICROSD_STATUS_IDX] = DEVSTATUS_MICROSD_OK;
	}
}


void File_FormatMicroSd(void)
{
	File_RWAllowed = 0;
	DevStatus[DEVSTATUS_MICROSD_STATUS_IDX] = DEVSTATUS_MICROSD_FAIL;

	(void)HAL_IWDG_Refresh(&hiwdg1);
	if (f_mkfs("0:", FM_FAT32, 4096, File_Buffer, sizeof(File_Buffer)) != FR_OK)
		return;
	f_mount(NULL, (TCHAR const*)SDPath, 1);
	if (f_mount(&File_SDFatFS, SDPath, 1) != FR_OK)
		return;
	File_RWAllowed = 1;
	DevStatus[DEVSTATUS_MICROSD_STATUS_IDX] = DEVSTATUS_MICROSD_OK;
}


void File_PrepareSdPowerDown(void)
{
	FATFS_UnLinkDriver(SDPath);
    HAL_SD_DeInit(&hsd2);
	f_mount(NULL, (TCHAR const*)SDPath, 1);
}


FIL* File_OpenReadFileFtp(const char* FileName)
{
	if (File_RWAllowed)
		if (f_open(&File_FileFtpId, FileName, FA_READ) == FR_OK)
			return &File_FileFtpId;
	return NULL;
}

uint32_t File_ReadFileFtp(FIL* File, uint8_t* Dest, uint32_t BufferSize)
{
	UINT ReadBytes = 20;
	strcpy((char*)Dest, "MicroSD status: fail");
	if ((File_RWAllowed) && (File != NULL))
		(void)f_read(File, Dest, BufferSize, &ReadBytes);
	return (uint32_t)ReadBytes;
}

void File_CloseFileFtp(FIL* File)
{
	if ((File_RWAllowed) && (File != NULL))
		(void)f_close(File);
}

uint32_t File_ReadFileNwm(const char* FileName, char* Dest)
{
	UINT ReadBytes = 0;
	if (File_RWAllowed)
		if (f_open(&File_FileNwmId, FileName, FA_READ) == FR_OK)
		{
			(void)f_read(&File_FileNwmId, Dest, 1024*1024, &ReadBytes);
			(void)f_close(&File_FileNwmId);
		}
	return (uint32_t)ReadBytes;
}

void File_WriteFileNwm(const char* FileName, const char* Src, uint32_t Size)
{
	UINT FileBytes;
	if (File_RWAllowed)
		if (f_open(&File_FileNwmId, FileName, FA_WRITE | FA_CREATE_ALWAYS) == FR_OK)
		{
			(void)f_write(&File_FileNwmId, (uint8_t*)Src, (UINT)Size, &FileBytes);
			(void)f_close(&File_FileNwmId);
		}
}

void File_WriteAppendFileNwm(const char* FileName, const char* Src)
{
	if (File_RWAllowed)
		if (f_open(&File_FileNwmId, FileName, FA_WRITE | FA_OPEN_APPEND) == FR_OK)
		{
			(void)f_printf(&File_FileNwmId, "%s\n", Src);
			(void)f_close(&File_FileNwmId);
		}
}


uint32_t File_ReadFile(const char* FileName, char* Dest)
{
	UINT ReadBytes = 0;
	if (File_RWAllowed)
		if (f_open(&File_FileId, FileName, FA_READ) == FR_OK)
		{
			(void)f_read(&File_FileId, Dest, 1024*1024, &ReadBytes);
			(void)f_close(&File_FileId);
		}
	return (uint32_t)ReadBytes;
}

void File_WriteFile(const char* FileName, const uint8_t* Src, uint32_t Size)
{
	UINT FileBytes;
	if (File_RWAllowed)
		if (f_open(&File_FileId, FileName, FA_WRITE | FA_CREATE_ALWAYS) == FR_OK)
		{
			(void)f_write(&File_FileId, Src, (UINT)Size, &FileBytes);
			(void)f_close(&File_FileId);
		}
}

void File_WriteFileAppend(const char* FileName, const uint8_t* Src, uint32_t Size)
{
	UINT FileBytes;

	if (File_RWAllowed)
		if (f_open(&File_FileId, FileName, FA_WRITE | FA_OPEN_APPEND) == FR_OK)
		{
			(void)f_write(&File_FileId, Src, (UINT)Size, &FileBytes);
			(void)f_close(&File_FileId);
		}
}

void File_DeleteFile(const char* FileName)
{
	if (File_RWAllowed)
		(void)f_unlink(FileName);
}


void File_SaveJpg(const char* PictureName, const uint8_t* Src, uint32_t Size)
{
	File_WriteFile(PictureName, Src, Size);
}

void File_SaveText(const char* TextName)
{
	UINT FileBytes;
	char* Dest = File_Buffer;
	struct Proc_ContourStruct* Contour;
	uint32_t C, I;
	uint8_t* Src;
	char Tmp[8];
	uint32_t Tmp32;

	if (File_RWAllowed)
		if (f_open(&File_FileId, TextName, FA_WRITE | FA_CREATE_ALWAYS) == FR_OK)
		{
			uint32_t XMin, YMin;
			Proc_GetImgXMinYMin(&XMin, &YMin);
			uint32_t ContoursNumber = Proc_GetNumberOfContours();

			for (C=0; C<ContoursNumber; C++)
			{
				Contour = Proc_GetContour(C);
				Dest = Utils_CopyString("Name: ", Dest);
				Dest = Utils_CopyString(Contour->ExtraData->Name, Dest);
				Dest = Utils_CopyString("\nLength: ", Dest);
				Dest = Utils_CopyString(Utils_Ftoa1(Contour->ExtraData->Length), Dest);
				Dest = Utils_CopyString("mm\nWidth: ", Dest);
				Dest = Utils_CopyString(Utils_Ftoa1(Contour->ExtraData->Width), Dest);
				Dest = Utils_CopyString("mm\nContour points: ", Dest);
				Dest = Utils_CopyString(itoa(Contour->PointsNumber, Tmp, 10), Dest);
				Dest = Utils_CopyString("\nContour start (X,Y): ", Dest);
				Dest = Utils_CopyString(itoa((Contour->XStart)-XMin, Tmp, 10), Dest);
				*Dest++ = ',';
				Dest = Utils_CopyString(itoa((Contour->YStart)-YMin, Tmp, 10), Dest);
				Dest = Utils_CopyString("\nContour: ", Dest);
				Src = Contour->Directions;
				for (I=0; I<(Contour->PointsNumber/2); I++)
				{
					Tmp32  = *Src++;
					Tmp32 += ((*Src++)<<3) + 60;
					*Dest++ = (uint8_t)Tmp32;
				}
				if (Contour->PointsNumber & 0x01)
					*Dest++ = (*Src) + 60;
				Dest = Utils_CopyString("\nHuMoments:", Dest);
				for (I=0; I<7; I++)
				{
					Dest = Utils_CopyString("\n", Dest);
					Dest = Utils_CopyString(Utils_Ftoa5(Contour->ExtraData->HuMoment[I]), Dest);
				}
				Dest = Utils_CopyString("\nCompactness: ", Dest);
				Dest = Utils_CopyString(Utils_Ftoa5(Contour->ExtraData->Compactness), Dest);
				Dest = Utils_CopyString("\nAngle: ", Dest);
				Dest = Utils_CopyString(Utils_Ftoa1(Contour->ExtraData->AngleDeg), Dest);
				*Dest++ = (char)176;
				Dest = Utils_CopyString("\nColor(RGB): ", Dest);
				Utils_IntToHexString(Contour->ExtraData->ColorRgbAvg, Dest, 6);
				Dest += 6;
				Dest = Utils_CopyString("\n\n", Dest);
			}

			(void)f_write(&File_FileId, (uint8_t*)File_Buffer, (UINT)(Dest-File_Buffer-2), &FileBytes);
			(void)f_close(&File_FileId);
		}
}
