#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         nHeight;    // количество строк
	int         nPitch;     // инкрементация адреса назначения после копирования строки спрайта
	uint32_t    nDstYAdd;   // 7е слово Y координата для видеорежима 256. слов в строке
	uint8_t     nSRCconst;  // константа заполнения или константа прозрачного цвета SRC
	uint8_t     nDSTconst;  // константа прозрачного цвета DST

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

	// чтение из памяти 8 слов команды
	// вход: ptr - указатель в памяти
	void read(uint16_t *ptr)
	{
		uint32_t w = *ptr++;	// первое слово: старший байт - старшая часть адреса SRC
								//               младший байт - старшая часть адреса DST
		nSRC = uint32_t(*ptr++) | (w & 0xff00) << 8; // 2 слово: младшая часть адреса SRC
		nDST = uint32_t(*ptr++) | (w & 0xff) << 16;  // 3 слово: младшая часть адреса DST
		nCMD = *ptr++;			// 4 слово: команда
		w = *ptr++;				// 5 слово:
		nWWidth = (w & 0xff) + 1;	// мл.байт длина спрайта в словах по горизонтали
		nHeight = (w >> 8) & 0xff;	// ст.байт количество строк (было в 7м слове)
		nPitch = ((*ptr++) & 0xff) - 1;	// 6 слово (используется младший байт) инкрементация адреса назначения после копирования строки спрайта
		nDstYAdd = (*ptr++) << 8;		// 7 слово: Y координата для видеорежима 256 слов в строке, иначе говоря это часть базового адреса для удобства
										//           addr_mem_dst <= addr_dst + {spr_Yadd, 8'd0};
		w = *ptr++;				// 8 слово:
		nSRCconst = w & 0xff;	// младший байт - константа заполнения или константа прозрачного цвета SRC
		nDSTconst = (w >> 8) & 0xff; // старший байт - константа прозрачного цвета DST
	}
};

constexpr uint16_t AZ_BLT_RUNNING = (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 - пуск
constexpr uint16_t AZ_BLT_READCMD = (1 << 9); // флаг чтения пачки команд: 1 - означает, что блиттер читает пачку команд в буфер и сейчас ничего с командами делать ничего нельзя. данный бит предназначен для организации конвейерной обработки пакетов команд

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

class AZ_Blitter
{
		uint16_t *m_pMainMemW;		// указатель на основную память AZBK в виде словного массива
		uint16_t	m_buffer[1024]; // внутренний буфер для хранения цепочки команд. 128*8
		AZ_BLITTER_t m_Cmd;			// параметры команды

		int			m_nCmd;			// количество команд в цепочке, если 0, то в буфере пусто
		int			m_nNumMoves;
		int			m_nCurCmd;		// номер текущей выполняемой команды
		int			m_nW;

		uint16_t	m_nReadCmds;	// флаг чтения пачки команд
		uint16_t	m_nRunning;		// флаг работы блиттера
		bool		m_bCmdFinished; // флаг получения следующей команды

		// временные параметры при выполнении команды
		bool		m_bNeedReadSrc;
		bool		m_bNeedReadDst;
		uint16_t   *m_adstw;
		uint16_t   *m_asrcw;
		uint8_t    *m_adstb;
		uint8_t    *m_asrcb;
		uint16_t	m_nFill000;

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

		inline uint16_t isRun() const
		{
			return m_nRunning;
		}

		inline uint16_t isReadCmds() const
		{
			return m_nReadCmds;
		}

		void		exec_chunk_cmd();
};
