// MSFManager.h: interface for the CMSFManager class.
//


#pragma once

#include "MSF.h"
#include "Config.h"

constexpr auto MSF_STATE_ID = 65536;
constexpr auto MSF_VERSION_MINIMAL = 20;
constexpr auto MSF_VERSION_CURRENT = 23;

class CMSFManager
{
		static const UINT  m_arBlkStrID[]; // массив строковых идентификаторов
	protected:
		FILE               *m_pMSFFile;
		bool                m_bOpenForLoad;
		MSF_FILE_HEADER     m_header;

		std::vector <MSF_BLOCK_INFO> m_blocks;

		bool                Seek(size_t nOffset, UINT nFrom) const;
		bool                ReleaseFile();

		bool                CheckBlockSize(MSF_BLOCK_INFO *pbi, DWORD size) const;
		bool                SetBlock(MSF_BLOCKTYPE bt, uint32_t id, const uint8_t *pData, UINT nSize, const bool bCompressed) const;
		bool                GetBlock(MSF_BLOCKTYPE bt, uint32_t id, uint8_t *pData, UINT nSize) const;

		bool                SetBlockHeader(MSF_BLOCK_INFO *pBi) const;
		bool                GetBlockHeader(MSF_BLOCK_INFO *pBi) const;
		bool                SetBlockData(const uint8_t *pBuff, UINT length) const;
		bool                GetBlockData(uint8_t *pBuff, UINT length) const;

		// функции упаковки/распаковки wav в tap
		mutable std::vector<std::vector<uint16_t>> m_vScanTable; // массив для упаковки/распаковки
		mutable int         m_nScanTableSize;

		void                InitTables() const;
		void                ClearTables() const;
		uint16_t            TableLookup_Fast(const uint16_t prefix, const uint8_t v) const;
		void                AddWord_Fast(const uint16_t prefix, const uint8_t v) const;
		bool                UnpackWord(uint8_t *pPackBits, size_t &p, uint16_t code) const;

	public:
		CMSFManager();
		virtual ~CMSFManager();

		bool                CheckFile(const fs::path &strPath, bool bSilent = false);
		bool                OpenFile(const fs::path &strPath, bool bLoad, bool bSilent = false);

		inline void         SetType(DWORD type)
		{
			m_header.type = type;
		}
		inline DWORD        GetType() const
		{
			return m_header.type;
		}

		inline void         SetVersion(DWORD version)
		{
			m_header.version = version;
		}
		inline DWORD        GetVersion() const
		{
			return m_header.version;
		}

		inline bool         IsLoad() const
		{
			return m_bOpenForLoad;
		}
		inline bool         IsSave() const
		{
			return !m_bOpenForLoad;
		}

		bool                FindBlock(MSF_BLOCKTYPE blockType, uint32_t id, MSF_BLOCK_INFO *pBi) const;

		bool                SetBlockTape(uint8_t *pPackedWave, DWORD nBitsLength, DWORD nPackLength) const;
		bool                GetBlockTape(uint8_t *pPackedWave, DWORD *pnBitsLength, DWORD *pnPackLength) const;

		bool                SetBlockPlatformData(MSF_PLATFORM_DATA *pPD) const;
		bool                GetBlockPlatformData(MSF_PLATFORM_DATA *pPD) const;

		bool                SetBlockPreview(HBITMAP hScreenshot) const;
		bool                SetBlockPreviewEx(HBITMAP hScreenshot, const bool bCompressed) const;
		bool                GetBlockPreview(HBITMAP *hScreenshot, uint8_t **pBits) const;

		bool                SetBlockConfig() const;
		bool                SetBlockConfigEx(const bool bCompressed) const;
		bool                GetBlockConfig() const;

		bool                SetBlockFrameData(MSF_FRAMEDATA *FDBlock) const;
		bool                GetBlockFrameData(MSF_FRAMEDATA *FDBlock) const;

		bool                SetBlockCPURegisters(MSF_CPU_REGISTERS *pCPURegisters) const;
		bool                GetBlockCPURegisters(MSF_CPU_REGISTERS *pCPURegisters) const;


		bool                GetBlockMemMap(uint32_t id, BKMEMBank_t *MBType, UINT nMemMapSize, uint32_t &nROMPresent) const;
		bool                SetBlockMemMap(uint32_t id, BKMEMBank_t *MBType, UINT nMemMapSize, uint32_t nROMPresent) const;

		bool                SetBlockBaseMemory(uint32_t id, const uint8_t *pMemory, UINT nSize) const;
		bool                SetBlockBaseMemoryEx(uint32_t id, const uint8_t *pMemory, UINT nSize, const bool bCompressed) const;
		bool                GetBlockBaseMemory(uint32_t id, const uint8_t *pMemory, UINT nSize) const;

		bool                SetBlockPortRegs(uint32_t id, MSF_PORT_REGS *pPortRegs) const;
		bool                GetBlockPortRegs(uint32_t id, MSF_PORT_REGS *pPortRegs) const;

		bool                SetBlockCustomData(MSF_BLOCKTYPE type, uint32_t id, uint8_t *pData, UINT nSize) const;
		bool                GetBlockCustomData(MSF_BLOCKTYPE type, uint32_t id, uint8_t *pData, UINT nSize) const;


		size_t              PackLZW_Fast(const uint8_t *pPackBits, const size_t nPackBitsLength, std::vector<uint16_t> &vPackLZW) const;
		void                UnpackLZW_Fast(uint8_t *pPackBits, const size_t nPackBitsLength, std::vector<uint16_t> const &vPackLZW) const;

};

