#include "pch.h"
#include "BKFloppyImage_Holography.h"
#include "StringUtil.h"


#pragma warning(disable:4996)

CBKFloppyImage_Holography::CBKFloppyImage_Holography(const PARSE_RESULT &image)
	: CBKFloppyImage_Prototype(image)
{
	m_vCatBuffer.resize(HOLO_CATALOG_SIZE);
	m_pDiskCat = reinterpret_cast<HolographyFileRecord *>(m_vCatBuffer.data()); // каталог диска
}

CBKFloppyImage_Holography::~CBKFloppyImage_Holography()
{
}

int CBKFloppyImage_Holography::FindRecord(const HolographyFileRecord *pPec) const
{
	for (int i = 0; i < m_nRecsNum; ++i) // цикл по всему каталогу
	{
		if (m_pDiskCat[i] == *pPec)
		{
			return i;
		}
	}

	return -1;
}


int CBKFloppyImage_Holography::FindRecord2(HolographyFileRecord *pPec, bool bFull /*= true*/)
{
	for (int i = 1; i < m_nRecsNum; ++i)
	{
		// сравниваем имя
		if (m_pDiskCat[i].name == pPec->name)
		{
			// если полное сравнение
			if (bFull)
			{
				// сравним ещё и другие параметры
				if (m_pDiskCat[i].length_blk == pPec->length_blk
				        && m_pDiskCat[i].load_address == pPec->load_address
				        && m_pDiskCat[i].start_address == pPec->start_address)
				{
					return i;
				}
			}
			else
			{
				return i;
			}
		}
	}

	return -1;
}

void CBKFloppyImage_Holography::ConvertAbstractToRealRecord(BKDirDataItem *pFR, bool bRenameOnly /*= false*/)
{
	auto pRec = reinterpret_cast<HolographyFileRecord *>(pFR->pSpecificData.data()); // Вот эту запись надо добавить

	// преобразовывать будем только если там ещё не сформирована реальная запись.
	if (pFR->nSpecificDataLength == 0 || bRenameOnly)
	{
		if (!bRenameOnly)
		{
			pFR->nSpecificDataLength = HOLO_REC_SIZE;
			pRec->clean();
		}

        std::wstring strName = strUtil::CropStr(pFR->pathName.wstring(), 16);
		imgUtil::UNICODEtoBK(strName, pRec->name, true);
		pRec->load_address = pFR->nAddress;
		pRec->length_blk = pFR->nBlkSize;
		pRec->start_block = pFR->nStartBlock;
		pRec->start_address = static_cast<uint16_t>(pFR->timeCreation); //тут будем хранить адрес запуска
	}
}

void CBKFloppyImage_Holography::ConvertRealToAbstractRecord(BKDirDataItem *pFR)
{
	auto pRec = reinterpret_cast<HolographyFileRecord *>(pFR->pSpecificData.data()); // Вот эту запись надо преобразовать

	if (pFR->nSpecificDataLength) // преобразовываем, только если есть реальные данные
	{
		pFR->pathName = strUtil::trim(imgUtil::BKToUNICODE(pRec->name, m_pKoi8tbl));
		pFR->nAttr = 0;
		pFR->nRecType = BKDirDataItem::RECORD_TYPE::FILE;
		pFR->nDirBelong = 0;
		pFR->nDirNum = 0;
		pFR->nAddress = pRec->load_address;
		pFR->nSize = pRec->length_blk * BLOCK_SIZE;
		pFR->nBlkSize = pRec->length_blk;
		pFR->nStartBlock = pRec->start_block;
		pFR->timeCreation = pRec->start_address; //тут будем хранить адрес запуска
	}
}



void CBKFloppyImage_Holography::GetSpecificData(BKDirDataItem *fr) const
{
	auto pRec = reinterpret_cast<HolographyFileRecord *>(fr->pSpecificData.data());
	fr->strSpecificColumn = std::format(L"{:06o}\0", pRec->start_address);
}

bool CBKFloppyImage_Holography::ReadCurrentDir()
{
	if (!CBKFloppyImage_Prototype::ReadCurrentDir())
	{
		return false;
	}

	memset(m_vCatBuffer.data(), 0, HOLO_CATALOG_SIZE);

	if (!SeekToBlkReadData(HOLO_CATALOG_BLK, m_vCatBuffer.data(), HOLO_CATALOG_SIZE)) // читаем каталог
	{
		return false;
	}

	m_nRecsNum = 0;
	m_nFreeBlock = HOLO_DATA_BLK;
	BKDirDataItem AFR; // экземпляр абстрактной записи
	auto pHoloRec = reinterpret_cast<HolographyFileRecord *>(AFR.pSpecificData.data()); // а в ней копия оригинальной записи
	int used_size = 0;

	for (int i = 0; i < HOLO_CATALOG_DIMENSION; ++i)
	{
		if (m_pDiskCat[i].length_blk == 0)
		{
			break; // конец каталога
		}

		m_nRecsNum++;
		// преобразуем запись и поместим в массив
		AFR.clear();
		AFR.nSpecificDataLength = HOLO_REC_SIZE;
		*pHoloRec = m_pDiskCat[i]; // копируем текущую запись как есть
		ConvertRealToAbstractRecord(&AFR);
		GetSpecificData(&AFR);
		used_size += AFR.nBlkSize; // удалённые файлы тоже считаются.
		m_nFreeBlock += AFR.nBlkSize; // с какого места начинается свободная область
		m_sDiskCat.vecFC.push_back(AFR);
	}

	m_sDiskCat.nTotalRecs = HOLO_CATALOG_DIMENSION;
	m_sDiskCat.nFreeRecs = m_sDiskCat.nTotalRecs - m_nRecsNum;
	const int imgSize = max(1600ul, m_sParseImgResult.nImageSize / m_nBlockSize); // NB! ОС работает только с 40 дорожками.
	m_sDiskCat.nTotalBlocks = imgSize - HOLO_DATA_BLK; // будем высчитывать это по размеру образа.
	m_sDiskCat.nFreeBlocks = m_sDiskCat.nTotalBlocks - used_size;
#ifdef _DEBUG
	DebugOutCatalog(m_pDiskCat);
#endif
	return true;
}



bool CBKFloppyImage_Holography::WriteCurrentDir()
{
#ifdef _DEBUG
	DebugOutCatalog(m_pDiskCat);
#endif

	if (!CBKFloppyImage_Prototype::WriteCurrentDir())
	{
		return false;
	}

	if (!SeekToBlkWriteData(HOLO_CATALOG_BLK, m_vCatBuffer.data(), HOLO_CATALOG_SIZE)) // сохраняем каталог как есть
	{
		return false;
	}

	return true;
}

bool CBKFloppyImage_Holography::ReadFile(BKDirDataItem *pFR, uint8_t *pBuffer)
{
	m_nLastErrorNumber = IMAGE_ERROR::OK_NOERRORS;
	bool bRet = true;
	ConvertAbstractToRealRecord(pFR);
	const size_t len = pFR->nSize;
	const size_t sector = pFR->nStartBlock;

	if (SeekToBlock(sector)) // перемещаемся к началу файла
	{
		// поскольку файл располагается единым куском, прочитаем его целиком
		if (len > 0)
		{
			if (!ReadData(pBuffer, len))
			{
				m_nLastErrorNumber = IMAGE_ERROR::IMAGE_CANNOT_READ;
				bRet = false;
			}
		}
	}
	else
	{
		bRet = false;
	}

	return bRet;
}


#ifdef _DEBUG
// отладочный вывод каталога
#pragma warning(disable:4996)
void CBKFloppyImage_Holography::DebugOutCatalog(HolographyFileRecord *pRec)
{
	fs::path strName = theApp.m_pathAppPath / L"dirlog.txt";
	FILE *log = _wfopen(strName.c_str(), L"wt");
	fprintf(log, "N#  FileName         block  length load.ad stаrt.ad\n");
	std::array<uint8_t, 17> name{};

	for (int i = 0; i < m_nRecsNum; ++i)
	{
		std::copy(pRec[i].name.begin(), pRec[i].name.end(), name.begin());
		name[16] = 0;
		fprintf(log, "%03d %-16s %06o %06o %06o  %06o\n", i, name.data(), pRec[i].start_block, pRec[i].length_blk, pRec[i].load_address, pRec[i].start_address);
	}

	fclose(log);
}
#endif
