#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    m_nSize{ 0 };        // размер образа в байтах
	uint32_t    m_nBlkSize{ 0 };     // размер образа в блоках
	uint32_t    m_nAttr{ 0 };        // атрибуты файла
	uint16_t    m_nDate{ 0 }, m_nTime{ 0 }; // дата/время в формате МС-ДОС
	bool        m_bRO{ false };          // Флаг защиты от записи
};


struct az_timestamp
{
	uint16_t rt11date{ 0 };
	uint16_t rt11time50h;
	uint16_t rt11time50l;
	uint16_t rt11time60h;
	uint16_t rt11time60l;
	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-Карты, там хранится всё нужное

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(uint32_t nBlk, void *buf, int size = 0) = 0;
		virtual bool writeBlock(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;
};

// режимы открытия файла
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 AZ_UNIT
{
		std::unique_ptr<io_unit_prototype> m_pIO;
		fs::path    m_fsFullOrigPathName; // полный оригинальный путь к файлу, если нет - то в этом слоте пусто, ничего не примонтировано

	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 &strFullFileName);

	public:
		AZ_UNIT();
		~AZ_UNIT();

		bool isReadOnly() const
		{
			return m_Params.m_bRO;
		}
		uint32_t getSize() const
		{
			return m_Params.m_nSize;
		}
		uint32_t getBlkSize() const
		{
			return m_Params.m_nBlkSize;
		}
		uint32_t getAttr() const
		{
			return m_Params.m_nAttr;
		}
		uint16_t getDate() const
		{
			return m_Params.m_nDate;
		}
		uint16_t getTime() const
		{
			return m_Params.m_nTime;
		}

		void setFulPathName(const fs::path &strFullFileName);
		fs::path getFulPathName() const;
		bool FillFileParameters();
		// функции
		bool Open(uint32_t mode);
		bool Open(const fs::path &strFullFileName, uint32_t mode);
		void Flush();
		void Close();
		int GetError(std::wstring &strError);
		bool ReadBlock(uint32_t blk, void *buf); // прочитать блок
		bool WriteBlock(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() {};

};

class io_unit_file : public io_unit_prototype
{
		FILE       *m_File;
		fs::path    m_fsFileName;   // имя файла
		intptr_t    m_hFile;
		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(uint32_t nBlk, void *buf, int size = 0) override;
		virtual bool writeBlock(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(uint32_t nBlk, void *buf, int size = 0) override;
		virtual bool writeBlock(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;
		}
};


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

