#pragma once

typedef enum
{
	RECORD_TYPE_UP = 0,
	RECORD_TYPE_DIR,
	RECORD_TYPE_LINK,
	RECORD_TYPE_LOGDSK,
	RECORD_TYPE_FILE
} AbstractRecordType;

#define COPY_BLOCK_SIZE 65536

typedef enum
{
	IMAGE_ERROR_OK = 0, //нет ошибок
	IMAGE_ERROR_NOT_ENOUGHT_MEMORY, //Недостаточно памяти.
	IMAGE_ERROR_FILE_CANNOT_OPEN,   //Невозможно открыть файл образа
	IMAGE_ERROR_FILE_CANNOT_CREATE, //Невозможно создать файл образа
	IMAGE_ERROR_FILE_NOT_OPEN,      //Файл образа не открыт
	IMAGE_ERROR_FILE_WRITE_PROTECRD, //Файл образа защищён от записи.
	IMAGE_ERROR_CANNOT_SEEK_FILE,   //Ошибка позиционирования в файле образа
	IMAGE_ERROR_CANNOT_READ_FILE,   //Ошибка чтения файла образа
	IMAGE_ERROR_CANNOT_WRITE_FILE,  //Ошибка записи в файл образа
	IMAGE_ERROR_CANNOT_CREATE_DIR,  //Невозможно создать директорию
	IMAGE_ERROR_FILE_NOT_FOUND,     //Файл(запись о файле в каталоге не найдена)
	IMAGE_ERROR_FS_FORMAT_ERROR,    //ошибка в формате файловой системы
	IMAGE_ERROR_FS_FILE_EXIST,      //Файл с таким именем уже существует.
	IMAGE_ERROR_FS_DIR_EXIST,       //Директория с таким именем уже существует.
	IMAGE_ERROR_FS_DIR_NOT_EXIST,   //Директории с таким именем не существует.
	IMAGE_ERROR_FS_CAT_FULL,        //Каталог заполнен.
	IMAGE_ERROR_FS_DISK_FULL,       //Диск заполнен.
	IMAGE_ERROR_FS_DISK_FULL_SQEEZE,    //Диск сильно фрагментирован, нужно провести сквизирование.
	IMAGE_ERROR_FS_DIR_NOT_EMPTY,   //Директория не пуста.
	IMAGE_ERROR_FS_STRUCT_ERR,      //Нарушена структура каталога.
	IMAGE_ERROR_IS_NOT_DIR,         //Это не директория. - попытка подсунуть файл функции change dir
	IMAGE_ERROR_IS_NOT_FILE,        //Это не файл. - попытка подсунуть не файл функции, работающей с файлами
	IMAGE_ERROR_FS_NOT_SUPPORT_DIRS, //Файловая система не поддерживает директории.
	IMAGE_ERROR_FS_FILE_PROTECTED,  //Файл защищён от удаления
	IMAGE_ERROR_NUMBER
} IMAGE_ERROR_NUMS;

extern wstring g_ImageErrorStr[];

// это правильная таблица
static const wchar_t koi8tbl_RFC1489[128] =
{
	//{200..237}
	0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524,
	0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590,
	0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248,
	0x2264, 0x2265, 0xA0,   0x2321, 0xB0,   0xB2,   0xB7,   0xF7,
	//{240..277}
	0x2550, 0x2551, 0x2552, 0x451,  0x2553, 0x2554, 0x2555, 0x2556,
	0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E,
	0x255F, 0x2560, 0x2561, 0x401,  0x2562, 0x2563, 0x2564, 0x2565,
	0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0xA9,
	//{300..337}
	L'ю', L'а', L'б', L'ц', L'д', L'е', L'ф', L'г',
	L'х', L'и', L'й', L'к', L'л', L'м', L'н', L'о',
	L'п', L'я', L'р', L'с', L'т', L'у', L'ж', L'в',
	L'ь', L'ы', L'з', L'ш', L'э', L'щ', L'ч', L'ъ',
	//{340..377}
	L'Ю', L'А', L'Б', L'Ц', L'Д', L'Е', L'Ф', L'Г',
	L'Х', L'И', L'Й', L'К', L'Л', L'М', L'Н', L'О',
	L'П', L'Я', L'Р', L'С', L'Т', L'У', L'Ж', L'В',
	L'Ь', L'Ы', L'З', L'Ш', L'Э', L'Щ', L'Ч', L'Ъ'
};


// это таблица кои8 БК11М
//таблица соответствия верхней половины аскии кодов с 128 по 255, включая псевдографику.
//выяснилось, что на бк11 таблица тоже нестандартная, но от бк10 тоже отличается.
static const wchar_t koi8tbl11M[128] =
{
	//{200..237}
	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
	0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
	0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
	0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
	//{240..277}
	0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
	0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
	0x25ba, 0x25c4, 0x2195, 0x203c, 0xb6,   0xa7,   0x25ac, 0x21a8,
	0x2191, 0x2193, 0x2192, 0x2190, 0x2fe,  0x2194, 0x25b2, 0x25bc,
	//{300..337}
	L'ю', L'а', L'б', L'ц', L'д', L'е', L'ф', L'г',
	L'х', L'и', L'й', L'к', L'л', L'м', L'н', L'о',
	L'п', L'я', L'р', L'с', L'т', L'у', L'ж', L'в',
	L'ь', L'ы', L'з', L'ш', L'э', L'щ', L'ч', L'ъ',
	//{340..377}
	L'Ю', L'А', L'Б', L'Ц', L'Д', L'Е', L'Ф', L'Г',
	L'Х', L'И', L'Й', L'К', L'Л', L'М', L'Н', L'О',
	L'П', L'Я', L'Р', L'С', L'Т', L'У', L'Ж', L'В',
	L'Ь', L'Ы', L'З', L'Ш', L'Э', L'Щ', L'Ч', L'Ъ'
};

//таблица соответствия верхней половины аскии кодов с 128 по 255, включая псевдографику
static const wchar_t koi8tbl10[128] =
{
	//{200..237} этих символов на бк10 нету.
	L' ', L' ', L' ', L' ', L' ', L' ', L' ', L' ',
	L' ', L' ', L' ', L' ', L' ', L' ', L' ', L' ',
	L' ', L' ', L' ', L' ', L' ', L' ', L' ', L' ',
	L' ', L' ', L' ', L' ', L' ', L' ', L' ', L' ',
	//{240..277}
	0xb6,    0x2534,  0x2665,  0x2510,  0x2561,  0x251c,  0x2514,  0x2550,
	0x2564,  0x2660,  0x250c,  0x252c,  0x2568,  0x2193,  0x253c,  0x2551,
	0x2524,  0x2190,  0x256c,  0x2191,  0x2663,  0x2500,  0x256b,  0x2502,
	0x2666,  0x2518,  0x256a,  0x2565,  0x2567,  0x255e,  0x2192,  0x2593,
	//{300..337}
	L'ю', L'а', L'б', L'ц', L'д', L'е', L'ф', L'г',
	L'х', L'и', L'й', L'к', L'л', L'м', L'н', L'о',
	L'п', L'я', L'р', L'с', L'т', L'у', L'ж', L'в',
	L'ь', L'ы', L'з', L'ш', L'э', L'щ', L'ч', L'ъ',
	//{340..377}
	L'Ю', L'А', L'Б', L'Ц', L'Д', L'Е', L'Ф', L'Г',
	L'Х', L'И', L'Й', L'К', L'Л', L'М', L'Н', L'О',
	L'П', L'Я', L'Р', L'С', L'Т', L'У', L'Ж', L'В',
	L'Ь', L'Ы', L'З', L'Ш', L'Э', L'Щ', L'Ч', L'Ъ'
};

static const wstring tblStrRec[3] =
{
	L"ь", L"и", L"ей"
};
static const wstring tblStrBlk[3] =
{
	L"", L"а", L"ов"
};

struct PaneInfo
{
	int nParentDir;
	int nCurDir;
	int nCurItem;
	wstring strCurrPath;    //текущий путь.
	PaneInfo()
	{
		clear();
	}
	void clear()
	{
		strCurrPath = L"/";
		nCurItem = nCurDir = 0;
		nParentDir = -1;
	}
};

#define FR_ATTR_READONLY 0x01
#define FR_ATTR_HIDDEN 0x02
#define FR_ATTR_PROTECTED 0x04
#define FR_ATTR_VOLUMEID 0x08
#define FR_ATTR_DIR 0x10
#define FR_ATTR_ARCHIVE 0x20
#define FR_ATTR_TEMPORARY 0x40
#define FR_ATTR_LOGDISK 0x80
#define FR_ATTR_LINK 0x100
#define FR_ATTR_BAD 0x200
#define FR_ATTR_DELETED 0x400


#define SPECIFIC_DATA_BUFFER_LENGTH 128
struct AbstractFileRecord
{
	wstring strName;            //имя
	unsigned int nAttr;         //атрибуты, ну там директория, защищённый, скрытый, удалённый, плохой
	AbstractRecordType nRecType;    //тип записи: 0="..", 1=директория, 2=ссылка, 3=логический диск, 4=простой файл, вводится специально для сортировки
	//поэтому частично дублирует атрибуты
	int nDirBelong;             //номер каталога, к которому принадлежит файл для файла и директории
	int nDirNum;                //номер директории для директории, 0 - для файла
	unsigned int nAddress;      //адрес файла, для директории 0, если для директории не 0, то это ссылка на другой диск.
	unsigned int nSize;         //размер файла
	int nBlkSize;               //размер в блоках, или кластерах (для андос)
	unsigned int nStartBlock;   //начальный сектор/блок/кластер
	bool bSelected;             //вводим флаг, что запись в списке выделена.
	time_t timeCreation;        //для ФС умеющих хранить дату создания файла
	//здесь будем хранить оригинальную запись о файле.
	uint32_t nSpecificDataLength; //размер записи о файле. на БК они гарантированно меньше 128 байтов
	uint8_t pSpecificData[SPECIFIC_DATA_BUFFER_LENGTH]; //буфер данных

	AbstractFileRecord()
	{
		clear();
	}
	~AbstractFileRecord()
	{
		this->strName.erase();
	}
	void clear()
	{
		this->strName.erase();
		this->nAttr = 0;
		this->nStartBlock = this->nBlkSize = this->nSize = this->nAddress = this->nDirNum = this->nDirBelong = 0;
		this->nRecType = RECORD_TYPE_UP;
		this->bSelected = false;
		this->nSpecificDataLength = 0;
		this->timeCreation = 0;
		memset(this->pSpecificData, 0, SPECIFIC_DATA_BUFFER_LENGTH);
	}
	AbstractFileRecord(const AbstractFileRecord *src)
	{
		this->strName = src->strName;
		this->nAttr = src->nAttr;
		this->nRecType = src->nRecType;
		this->nDirBelong = src->nDirBelong;
		this->nDirNum = src->nDirNum;
		this->nAddress = src->nAddress;
		this->nSize = src->nSize;
		this->nBlkSize = src->nBlkSize;
		this->nStartBlock = src->nStartBlock;
		this->bSelected = src->bSelected;
		this->timeCreation = src->timeCreation;
		this->nSpecificDataLength = src->nSpecificDataLength;
		memcpy(this->pSpecificData, src->pSpecificData, SPECIFIC_DATA_BUFFER_LENGTH);
	}
	AbstractFileRecord &operator = (const AbstractFileRecord &src)
	{
		this->strName = src.strName;
		this->nAttr = src.nAttr;
		this->nRecType = src.nRecType;
		this->nDirBelong = src.nDirBelong;
		this->nDirNum = src.nDirNum;
		this->nAddress = src.nAddress;
		this->nSize = src.nSize;
		this->nBlkSize = src.nBlkSize;
		this->nStartBlock = src.nStartBlock;
		this->bSelected = src.bSelected;
		this->timeCreation = src.timeCreation;
		this->nSpecificDataLength = src.nSpecificDataLength;
		memcpy(this->pSpecificData, src.pSpecificData, SPECIFIC_DATA_BUFFER_LENGTH);
		return *this;
	}
};

struct DiskCatalog
{
	vector<AbstractFileRecord> vecFC; //текущий каталог
	vector<int>vecDir;      //вектор номеров вложенных каталогов.
	int nCurrDirNum;        //номер текущего каталога.
	bool bHasDir;       //флаг, имеет ли файловая система директории
	int nMaxDirNum;     //максимальный номер директории на диске. нужно, чтобы создавать новые директории.
	//переменные для отображения информации о ФС диска
	int nTotalRecs;     //всего записей в каталоге
	int nTotalBlocks;   //общее количество блоков/кластеров (зависит от ФС)
	int nFreeRecs;      //количество свободных записей в каталоге
	int nFreeBlocks;    //количество свободных блоков/кластеров (зависит от ФС) на основе чего высчитывается кол-во свободных байтов
	int nDataBegin;     //блок, с которого начинаются данные на диске (зависит от ФС)
};

//структура для передачи параметров анализатору файлов
struct AnalyseFileStruct
{
	FILE *file;
	wstring strName;
	wstring strExt;
	int nOffset;
	int nAddr;
	int nLen;
};


wstring BKToUNICODE(uint8_t *pBuff, int size, const wchar_t table[]);
wchar_t BKToUNICODE_Byte(uint8_t b, const wchar_t table[]);

void UNICODEtoBK(const wstring &ustr, uint8_t *pBuff, size_t bufSize, bool bFillBuf = false);

void SetSafeName(wstring &str);
void SetSafeDir(wstring &str);

//получим номер окончания слова в зависимости от числа num
unsigned int GetWordEndIdx(unsigned int num);

//удаление заданного символа с обоих концов строки
void trim(wstring *str, wchar_t trim_char = L' ');
//удаление заданного символа в начале строки
void trimLeft(wstring *str, wchar_t trim_char = L' ');
//удаление заданного символа в конце строки
void trimRight(wstring *str, wchar_t trim_char = L' ');
//замена всех символов src в строке на символы dst
void replaceChar(wstring *str, wchar_t src, wchar_t dst);
//замена всех символов, входящих в src в строке на символы dst
void replaceChars(wstring *str, wstring &src, wchar_t dst);

void strToUpper(wstring *str);
void strToLower(wstring *str);

