#pragma once

//набор структур, енумов и функций скопирован из BKParseImage из BKDE, если там что-то поменяется, тут тоже не забыть поменять
enum IMAGE_TYPES : int
{
	IMAGE_TYPE_ERROR = -1,
	IMAGE_TYPE_UNKNOWN = 0,
	IMAGE_TYPE_ANDOS,
	IMAGE_TYPE_MKDOS,
	IMAGE_TYPE_AODOS,
	IMAGE_TYPE_NORD,
	IMAGE_TYPE_MIKRODOS,
	IMAGE_TYPE_CSIDOS3,
	IMAGE_TYPE_RT11,
	IMAGE_TYPE_NCDOS,
	IMAGE_TYPE_DXDOS,
	IMAGE_TYPE_MSDOS
};

struct PARSE_RESULT
{
	UINT nImageSize;
	UINT nBaseOffset;
	IMAGE_TYPES imageOSType;
	bool bImageBootable;
	CString strName;

	PARSE_RESULT()
	{
		clear();
	}

	~PARSE_RESULT()
	{
		this->strName.Empty();
	}

	void clear()
	{
		this->nBaseOffset = this->nImageSize = 0;
		this->imageOSType = IMAGE_TYPE_UNKNOWN;
		this->bImageBootable = false;
		this->strName = _T("");
	}

	PARSE_RESULT(const PARSE_RESULT *src)
	{
		this->nImageSize = src->nImageSize;
		this->nBaseOffset = src->nBaseOffset;
		this->imageOSType = src->imageOSType;
		this->bImageBootable = src->bImageBootable;
		this->strName = src->strName;
	}

	PARSE_RESULT &operator = (const PARSE_RESULT &src)
	{
		this->nImageSize = src.nImageSize;
		this->nBaseOffset = src.nBaseOffset;
		this->imageOSType = src.imageOSType;
		this->bImageBootable = src.bImageBootable;
		this->strName = src.strName;
		return *this;
	}
};

#define SECTOR_SIZEB 512
#define SECTOR_SIZEW 256


//структура параметров образа винчестера. Функционал взят из BKHDDTool
//если там что-то поменяется, не забыть поменять тут
struct IMGFormat
{
	bool bHDI;  //признак образа в формате HDI
	bool bSamara; //флаг формата самара
	int nLogDiskNum; //количество разделов
	WORD C; //геометрия: количество дорожек
	WORD H; //геометрия: количество головок
	WORD S; //геометрия: количество секторов на дорожке
	WORD nCyl;  //текущий номер дорожки при формировании образа
	WORD nHead; //текущий номер головки при формировании образа
	WORD nSector;   //текущий номер сектора при формировании образа
	IMGFormat()
	{
		this->bHDI = false;
		this->bSamara = false;
		this->nLogDiskNum = 0;
		this->C = 0;
		this->H = 0;
		this->S = 0;
		this->nCyl = 0;
		this->nHead = 0;
		this->nSector = 0;
	}
	IMGFormat(const IMGFormat *src)
	{
		this->bHDI = src->bHDI;
		this->bSamara = src->bSamara;
		this->nLogDiskNum = src->nLogDiskNum;
		this->C = src->C;
		this->H = src->H;
		this->S = src->S;
		this->nCyl = src->nCyl;
		this->nHead = src->nHead;
		this->nSector = src->nSector;
	}
	IMGFormat &operator = (const IMGFormat &src)
	{
		this->bHDI = src.bHDI;
		this->bSamara = src.bSamara;
		this->nLogDiskNum = src.nLogDiskNum;
		this->C = src.C;
		this->H = src.H;
		this->S = src.S;
		this->nCyl = src.nCyl;
		this->nHead = src.nHead;
		this->nSector = src.nSector;
		return *this;
	}
};

struct RT11SegmentHdr
{
	WORD segments_num;  //число сегментов, отведённых под каталог
	WORD next_segment;  //номер следующего сегмента каталога, если 0 - то этот сегмент последний
	WORD used_segments; //счётчик сегментов, имеющих записи, есть только в первом сегменте
	WORD filerecord_add_bytes;   //число дополнительных БАЙТОВ! в записи о файле в каталоге
	WORD file_block;    //номер блока, с которого начинается самый первый файл, описанный в данном сегменте

	RT11SegmentHdr()
	{
		memset(this, 0, sizeof(RT11SegmentHdr));
	}
	RT11SegmentHdr &operator = (const RT11SegmentHdr &src)
	{
		memcpy(this, &src, sizeof(RT11SegmentHdr));
		return *this;
	}
	RT11SegmentHdr &operator = (const RT11SegmentHdr *src)
	{
		memcpy(this, src, sizeof(RT11SegmentHdr));
		return *this;
	}
};


// CLoadImgDlg

class CLoadImgDlg : public CFileDialog
{
		DECLARE_DYNAMIC(CLoadImgDlg)

		//это сектор. чтобы удобнее было делать одновременно байтовый и словный доступ
		typedef union
		{
			BYTE b[SECTOR_SIZEB];
			WORD w[SECTOR_SIZEW];
		} USector;

		static const char *strID_Andos;
		static const char *strID_DXDOS;
		static const char *strID_FAT12;
		static const char *strID_Aodos;
		static const char *strID_Nord;
		static const char *strID_Nord_Voland;
		static const char *strID_RT11;
		static const char *strID_RT11Q;

		static UINT_PTR CALLBACK OFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam);
		static void DrawPreview(HWND hdlg, const CString &strPath);

		static USector m_sector;

	public:
		CLoadImgDlg(BOOL bOpenFileDialog, // TRUE для FileOpen, FALSE для FileSaveAs
		            LPCTSTR lpszDefExt = nullptr,
		            LPCTSTR lpszFileName = nullptr,
		            DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
		            LPCTSTR lpszFilter = nullptr,
		            CWnd *pParentWnd = nullptr,
		            DWORD dwSize = 0,
		            BOOL bVistaStyle = FALSE); //если сделать FALSE в Win7 в отладочной версии случается debug assertion, впрочем не влияющий на работу.
		//если bVistaStyle = TRUE то не работают хуки, и принципиально невозможно как-то свою информацию показывать.
		virtual ~CLoadImgDlg() override;

	protected:
		static bool charcompare(BYTE a, BYTE b);
		static bool substrfind(BYTE *bufs, size_t len_bufs, BYTE *buff, size_t len_buff);
		static bool ReadLBA(FILE *f, void *buffer, UINT lba, int numSectors);

		static PARSE_RESULT ParseImage(const CString &fname, UINT nBaseOffset);
		static int IsCSIDOS3(FILE *f, UINT nBaseOffsetLBA, BYTE *buf);
		static int IsRT11_old(FILE *f, UINT nBaseOffsetLBA, BYTE *buf);
		static int IsRT11(FILE *f, UINT nBaseOffsetLBA, BYTE *buf, UINT nFileSize);
		static int AnalyseMicrodos(FILE *f, UINT nBaseOffsetLBA, BYTE *buf);
		static void GetImgFormat(const CString &strImageName, CString &strFormatName, CString &strSystemFlag);

		static bool AnalyseImage(const CString &fname, IMGFormat * pFormat);
		static void InverseSector(USector & sector);
		static bool CheckFormat(FILE * f, IMGFormat * pFormat);
		static bool CheckAltPro(FILE * f, IMGFormat * imgf);
		static bool CheckSamara(FILE * f, IMGFormat * imgf);

		DECLARE_MESSAGE_MAP()
};


