#pragma once

#include "AZBK_Network.h"

constexpr auto AZ_FNAME_BUFSIZE = 386;  // длина буфера под имя файла

// элемент внутренней таблицы назначений.
#pragma pack(push)
#pragma pack(1)
struct az_internal_table
{
	uint32_t    size{0};
	uint16_t    date{0};
	uint16_t    time{0};
	uint8_t     flag{0};
	uint8_t     attr{0};
	std::array<char, AZ_FNAME_BUFSIZE> name{};
};

constexpr auto HFSFnameLen = 13;
struct az_HFSitem
{
	uint32_t    fsize{0};
	uint16_t    fdate{0};
	uint16_t    ftime{ 0 };
	uint8_t     fattrib{ 0 };
	std::array<char, HFSFnameLen> fname;
};

struct az_UnitParams
{
	uint32_t    nSize{ 0 };			// размер образа в байтах
	uint32_t    nBlkSize{ 0 };		// размер образа в блоках
	uint32_t    nAttr{ 0 };			// атрибуты файла
	uint16_t    nDate{ 0 }, nTime{ 0 }; // дата/время в формате МС-ДОС
	bool        bRO{ false };       // Флаг защиты от записи
};


struct az_timestamp
{
	uint16_t	rt11date{ 0 };
	uint16_t	rt11time50h{0};
	uint16_t	rt11time50l{0};
	uint16_t	rt11time60h{0};
	uint16_t	rt11time60l{0};
	uint16_t	fatdate{ 0 };
	uint16_t	fattime{ 0 };
	uint16_t	year{ 0 };
	uint16_t	month{ 0 };
	uint16_t	day{ 0 };
	uint16_t	wday{ 0 };
	uint16_t	hour{ 0 };
	uint16_t	min{ 0 };
	uint16_t	sec{ 0 };
};
#pragma pack(pop)

// TODO: перенести потом когда-нибудь в Config
extern fs::path g_strConfImgPath;   // путь к содержимому SD-Карты, там хранится всё нужное

// режимы открытия файла
constexpr uint32_t AZIO_OPEN_RD = 1;
constexpr uint32_t AZIO_OPEN_WR = 2;
constexpr uint32_t AZIO_OPEN_RW = AZIO_OPEN_WR | AZIO_OPEN_RD;
constexpr uint32_t AZIO_OPEN_CR = 4; // создание файла, если файл существует - перезаписать

constexpr auto AZIO_BLK_SIZE = 512; // размер блока

class io_unit_prototype
{
	protected:
		TCHAR       m_chRoot{ 0 };  // имя корневого устройства

	public:
		io_unit_prototype(TCHAR ch)
			: m_chRoot(ch)
		{};
		virtual ~io_unit_prototype()
			= default;
		virtual bool	FillFileParameters(const fs::path &fsFullFilePath, az_UnitParams &params) const = 0;
		virtual bool	open(const fs::path &fsFullFilePath, az_UnitParams &params, uint32_t mode) = 0;
		virtual void	close() = 0;
		virtual int		getError(std::wstring &strError) const = 0;
		virtual bool	readBlock(const uint32_t nBlk, void *buf, int size = 0) = 0;
		virtual bool	writeBlock(const uint32_t nBlk, void *buf, int size = 0) = 0;

		virtual bool	openDir(const fs::path &strFullPath) = 0;
		virtual bool	readDir(az_HFSitem *p, az_UnitParams &params) = 0;
		virtual bool	searchDir() = 0;
};


class io_unit_file : public io_unit_prototype
{
		FILE           *m_File{ nullptr };
		fs::path        m_fsFileName;   // имя файла
		intptr_t        m_hFile{ 0 };	// это для получения содержимого каталога
		struct _wfinddata_t m_file{};	// это тоже

		fs::path		ParseFilePathName(const fs::path &str) const;
	public:
		io_unit_file(TCHAR ch);
		virtual ~io_unit_file() override
		{
			close();
		}
		virtual bool	FillFileParameters(const fs::path &fsFullFilePath, az_UnitParams &params) const override;
		virtual bool	open(const fs::path &fsFullFilePath, az_UnitParams &params, uint32_t mode) override;
		virtual void	close() override;
		virtual int		getError(std::wstring &strError) const override;
		virtual bool	readBlock(const uint32_t nBlk, void *buf, int size = 0) override;
		virtual bool	writeBlock(const uint32_t nBlk, void *buf, int size = 0) override;

		virtual bool	openDir(const fs::path &strFullPath) override;
		virtual bool	readDir(az_HFSitem *p, az_UnitParams &params) override;
		virtual bool	searchDir() override
		{
			// это пока не реализовано в реальном железе и незнай как делать пока
			return false;
		}
};

class io_unit_net : public io_unit_prototype
{
		std::string		fsCurrentFilePath;
		int				m_error{ 0 };
		std::array<uint8_t, AZNetwork::LANDISK_DATA_SIZE> m_tmp{}; // временный буфер.

	public:
		io_unit_net(TCHAR ch);
		virtual ~io_unit_net() override;
		virtual bool	FillFileParameters(const fs::path &fsFullFilePath, az_UnitParams &params) const override;
		virtual bool	open(const fs::path &fsFullFilePath, az_UnitParams &params, uint32_t mode) override;
		virtual void	close() override;
		virtual int		getError(std::wstring &strError) const override;
		virtual bool	readBlock(const uint32_t nBlk, void *buf, int size = 0) override;
		virtual bool	writeBlock(const uint32_t nBlk, void *buf, int size = 0) override;

		virtual bool	openDir(const fs::path &strFullPath) override;
		virtual bool	readDir(az_HFSitem *p, az_UnitParams &params) override;
		virtual bool	searchDir() override
		{
			// это пока не реализовано в реальном железе и незнай как делать пока
			return false;
		}
};


class AZ_UNIT
{
		std::unique_ptr<io_unit_prototype> m_pIO;
		fs::path        m_pathFullOrigPathName; // полный оригинальный путь к файлу, если нет - то в этом слоте пусто, ничего не примонтировано

	protected:
		az_UnitParams   m_Params{};
		bool            m_bWrite{ false };      // флаг открытия файла для записи
		int             m_nCurrentBlock{ 0 };
		int             m_wrkPtr{ 0 };      // указатель во временном буфере
		std::array<uint8_t, AZNetwork::LANDISK_DATA_SIZE> m_wrkBuf{}; // временный буфер.

		bool            ParseRootDev(const fs::path &pathFullFileName);

	public:
		AZ_UNIT();
		~AZ_UNIT();

		bool			isReadOnly() const
		{
			return m_Params.bRO;
		}
		uint32_t		getSize() const
		{
			return m_Params.nSize;
		}
		uint32_t		getBlkSize() const
		{
			return m_Params.nBlkSize;
		}
		uint32_t		getAttr() const
		{
			return m_Params.nAttr;
		}
		uint16_t		getDate() const
		{
			return m_Params.nDate;
		}
		uint16_t		getTime() const
		{
			return m_Params.nTime;
		}

		void			setFulPathName(const fs::path &pathFullFileName)
		{
			m_pathFullOrigPathName = pathFullFileName;
		}
		const fs::path &getFulPathName() const
		{
			return m_pathFullOrigPathName;
		}

		bool			FillFileParameters();
		// функции
		bool			Open(uint32_t mode);
		bool			Open(const fs::path &pathFullFileName, uint32_t mode);
		void			Flush();
		void			Close();
		int				GetError(std::wstring &strError);
		bool			ReadBlock(const uint32_t blk, void *buf); // прочитать блок
		bool			WriteBlock(const uint32_t blk, void *buf); // записать блок
		uint32_t		ReadFile(const uint8_t *buf, uint32_t len); // прочитать файл целиком
		uint32_t		WriteFile(const uint8_t *buf, uint32_t len); // записать файл целиком
		bool			GetF(const uint8_t *buf, uint32_t len); // поточное чтение данных, начиная с текущего блока
		bool			PutF(const uint8_t *buf, uint32_t len); // поточная запись данных, начиная с текущего блока
		//работа с каталогами
		bool			OpenDir(const fs::path &strFullPath);
		bool			ReadDir(az_HFSitem *p);
		void			SearchDir()
		{};

};

/*
будет 4 пространства сетевых дисков
N:/ - это архив в текущем виде - те все что угодно можно монтировать
R:/ репозиторий - буду формировать внятный набор дисков - прошу коллег подключаться к этому процессу
P:/ - персональное облако, будет доступно и на запись
но доступ только для себя
S:/ - shared - облако для возможности делится с кем-то дисками и доступом к ним
досутп будет управляемый
*/

