#pragma once
#include <thread>
#include <mutex>
#include <condition_variable>

// параметры команды блиттера
struct AZ_BLITTER_t
{
	uint32_t    nSRC;       // 24 битный адрес источника в словах
	uint32_t    nDST;       // 24 битный адрес приёмника в словах
	uint16_t    nCMD;       // команда
	int         nWWidth;    // длина спрайта в словах по горизонтали
	int         nPitch;     // инкрементация адреса назначения после копирования строки спрайта
	int         nHeight;    // количество строк
	uint8_t     nSRCconst;  // константа заполнения или константа прозрачного цвета SRC
	uint8_t     nDSTconst;  // константа прозрачного цвета DST

	void clear()
	{
		nSRC = nDST = nCMD = nWWidth = nPitch = nHeight = nSRCconst = nDSTconst = 0;
	}

	// чтение из памяти 8 слов команды
	// вход: ptr - указатель в памяти
	void read(uint16_t *ptr)
	{
		uint32_t w = *ptr++; // первое слово
		nSRC = uint32_t(*ptr++) | (w & 0xff00) << 8; // 2 слово
		nDST = uint32_t(*ptr++) | (w & 0xff) << 16; // 3 слово
		nCMD = *ptr++; // 4 слово
		nWWidth = ((*ptr++) & 0xff) + 1; // 5 слово
		nPitch = ((*ptr++) & 0xff) - 1; // 6 слово
		nHeight = (*ptr++) & 0xff; // 7 слово
		w = *ptr++; // 8 слово
		nSRCconst = w & 0xff;
		nDSTconst = (w >> 8) & 0xff;
	}
};

constexpr uint16_t AZ_BLT_DOEXEC = (1 << 15); // флаг выполнения блиттером команд (RO): 1 - работает, 0 - не работает
constexpr uint16_t AZ_BLT_MANUAL = (1 << 14); // флаг ручного режима (RW): 0 - ручной, 1 - автоматический
constexpr uint16_t AZ_BLT_RUNMAN = (1 << 12); // флаг ручного запуска (WO): 1 - пуск

extern HANDLE	g_evBltSync;	// флаг формирования одной строки VGA

constexpr int AZ_BLTCMDInLineNum = 100;	// количество пересылок, которое выполняется за время прорисовки одной строки VGA
constexpr uint32_t AZ_BLTWAITTIME = INFINITE;	// время ожидания события прорисовки строки, в мс.

class AZ_Blitter
{
		uint16_t *m_pMainMemW; // указатель на основную память AZBK в виде словного массива

		struct PrepData
		{
			int     nCmd;   // количество команд в цепочке
			int     nAddr; // адрес в основной памяти, где находится цепочка команд
		};

		std::thread	m_thrExec;
		std::mutex	m_mutExec;
		std::mutex	m_mutExecSyn;
		std::condition_variable m_cvExec;

		bool		StartExecThread();
		void		StopExecThread();
		void		ExecThread();

		bool		exec_cmd(AZ_BLITTER_t *pCmd);

		uint16_t	m_buffer[1024]; // внутренний буфер для хранения цепочки команд.
		int			m_nCmd; // количество команд в цепочке, если 0, то в буфере пусто
		int			m_nNumMoves;

		bool		m_pExecThreadNotify;
		bool		m_bExecThreadTerminate;
		volatile bool m_bReset;
		volatile bool m_bExecFlag;

	public:
		AZ_Blitter();
		~AZ_Blitter();
		void		AttachMemory(uint16_t *pMainMemW);
		void		DoExec(const int nCmd, const int nAddr);
		void		Reset();
		inline bool isExec() const
		{
			return m_bExecFlag;
		}
};
