#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;
	}
};

#define PREPARE_THREAD 0

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

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

#if (PREPARE_THREAD)
		std::thread m_thrPrepare;
		std::mutex m_mutPrepare;
		std::mutex m_mutPrepSyn;
		std::condition_variable m_cvPrepare;

		std::vector<PrepData> m_vPrepNotify;
		bool m_bPrepThreadTerminate;

		bool StartPrepThread();
		void StopPrepThread();
		void PrepareThread();
#endif

		std::thread m_thrExec;
		std::mutex m_mutExec;
		std::mutex m_mutExecSyn;
		std::condition_variable m_cvExec;
		bool m_pExecThreadNotify;
		bool m_bExecThreadTerminate;

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

		void exec_cmd(AZ_BLITTER_t *pCmd);

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

		volatile bool m_bReset;

	public:
		AZ_Blitter();
		~AZ_Blitter();
		void AttachMemory(uint16_t *pMainMemW);
		void DoPrepare(int nCmd, int nAddr);
		void DoExec();
		void Reset();
};
