#include "pch.h"

#include "AZBK.h"

#pragma warning(disable:4996)

/* Команда 044.
* 1. берём из CAZBKController::az_cmosmem имя, и делаем из него CString
* 2. сохраняем этот CString локально
* 3. вызываем функцию simple_save_memory_to_file
* 4. по результату функции выставляем флаг ошибки, и если CString изменился
*    помещаем новое имя в CAZBKController::az_cmosmem
*/
bool CAZBKController::cmd044func()
{
	// получаем указатель на буфер. там 512 байтов
	auto pName = reinterpret_cast<uint8_t *>(az_cmosmem.data());
	// преобразуем имя в строку, имеем в виду, что там может быть мусор.
	// и наша строка будет полное говно.
	CString strName = Global::BKToUNICODE(std::span{ pName, AZIO_BLK_SIZE });
	int res = simple_save_memory_to_file(&strName);
	// возвращаем имя в буфер обратно
	Global::UNICODEtoBK(strName, std::span{ pName, AZIO_BLK_SIZE }, false);
	return !!res;
}


CString CAZBKController::gen_filename_for_screen()
{
	constexpr auto nBufSize = 80;
	std::array<TCHAR, nBufSize> buf{};
	const time_t    now = time(nullptr);
	const struct tm tstruct = *localtime(&now);
	_tcsftime(buf.data(), nBufSize, _T("%d%H%M%S"), &tstruct);
	return _T("0:/SCREENS/") + CString(buf.data()) + _T(".SCR");
}


// обёртка для сохранения скриншота по параметрам в контрольной странице
// опционально принимает на вход имя файла, если имени нет - генерит своё и соответственно его возвращает
// если при создании скриншота возникнет ошибка - возвращает её виде строки
bool CAZBKController::simple_save_memory_to_file(CString *screen_filename)
{
	AZ_UNIT     file_screen;
	std::array<uint8_t, 1024> buf{}; // буфер
	uint32_t    bw = 0; // количество записанных байт
	uint32_t    begin_adress0{}, begin_adress1{}, begin_adress2{};
	uint32_t    length_in_words0 = 0, length_in_words1 = 0, length_in_words2 = 0;
	auto        sch = reinterpret_cast<screen_header_t *>(buf.data());  // мы готовы рассматривать буфер как структуру для получения информации о скриншоте

	if (screen_filename->GetLength() < 10) // если строка некорретная - генерим свое имя
	{
		*screen_filename = gen_filename_for_screen();
	}

	if (file_screen.Open(*screen_filename, AZIO_OPEN_CR | AZIO_OPEN_WR)) // проверим успешность открытия файла индекса на запись
	{
		// читаем 1024 байт 76й страницы в буфер
		uint32_t adress_to_read = AZ_BANK_TO_OFFSET(076); // 076ая страница
		memcpy(buf.data(), m_pAZMainMemory + adress_to_read, 1024);
		// пишем блок хидера
		file_screen.PutF(buf.data(), 1024);

		// теперь надо разобраться с переданными параметрами
		if (sch->length > 0 && sch->length <= 1024 * 1024) // максимальная порция - 2МБ
		{
			begin_adress0 = sch->begin_adress * 2; // из слов в байты
			length_in_words0 = sch->length;
			TRACE("simple_save_memory_to_file>sch->length=%d sch->length=%d \n\r", sch->length, sch->length);
		}
		else if (sch->len_pages > 0 && sch->len_pages <= AZIO_BLK_SIZE) // максимальная порция - 2МБ
		{
			begin_adress0 = AZ_BANK_TO_OFFSET(sch->begin_page); // пересчитываем в адреса
			length_in_words0 = sch->len_pages * 2048;
			TRACE("simple_save_memory_to_file>sch->begin_page=%d sch->len_pages=%d \n\r", sch->begin_page, sch->len_pages);
		}
		else // остается автоопределение
		{
			int roll_size = 0, v_px = 0, h_px = 0, color_depth = 0, len_str = 0;
			// размер рулона - биты 15 14 13 12
			const uint16_t roll_size_bit = (sch->R177230 & 0170000) >> 12;

			switch (roll_size_bit)
			{
				case 0:  roll_size = 6144; break;

				case 1:  roll_size = 8192; break;

				case 2:  roll_size = 12288; break;

				case 3:  roll_size = 16384; break;

				case 4:  roll_size = 24576; break;

				case 5:  roll_size = 32768; break;

				case 6:  roll_size = 49152; break;

				case 7:  roll_size = 65536; break;

				case 8:  roll_size = 98304; break;

				case 9:  roll_size = 131072; break;

				case 10: roll_size = 196608; break;

				case 11: roll_size = 262144; break;

				default: roll_size = 8192;
			}   // получена длина всего рулона, но надо понимать что может отображаться не весь рулон!

			// получим количество бит на пиксель
			const uint16_t color_depth_bit = (sch->R177230 & 03);  // бит на 1 ц

			switch (color_depth_bit)
			{
				case 0:  color_depth = 1; break;

				case 1:  color_depth = 2; break;

				case 2:  color_depth = 4; break;

				case 3:  color_depth = 8; break;
			}

			// длина строки - физическая
			const uint16_t len_str_bit = (sch->R177230 & 030) >> 3;

			switch (len_str_bit)
			{
				case 0:  len_str = 32;  break;

				case 1:  len_str = 64;  break;

				case 2:  len_str = 128; break;

				case 3:  len_str = 256; break;
			}

			// разрешение по горизонтали
			const uint16_t h_px_bit = (sch->R177230 & 0300) >> 6;

			switch (h_px_bit)
			{
				case 0:  h_px = 1024; break;

				case 1:  h_px = 512;  break;

				case 2:  h_px = 256;  break;

				case 3:  h_px = 128;  break;
			}

			// разрешение по вертикали
			const uint16_t v_px_bit = (sch->R177230 & 03000) >> 9;

			switch (v_px_bit)
			{
				case 0:  v_px = 768; break;

				case 1:  v_px = 384; break;

				case 2:  v_px = 256; break;

				case 3:  v_px = 192; break;
			}

			// вычислим физический размер отображемой части в словах
			const int view_h_size = h_px * color_depth / 8 / 2;     // длина строки в словах
			const int view_size = v_px * view_h_size;               // в словах
			TRACE("simple_save_memory_to_file> roll_size=%d view_size=%d color_depth=%d len_str=%d resolution %dx%d  177230=%o\n\r", roll_size, view_size, color_depth, len_str, h_px, v_px, sch->R177230);
			begin_adress0 = AZ_BANK_TO_OFFSET(sch->R177232); // пересчитываем в адреса
			length_in_words0 = roll_size;                   // тащим всегда рулон

			if (sch->R177230 & 0x0004) // это слоеный режим
			{
				//printf("simple_save_memory_to_file> puff mode on\n\r");
				begin_adress1 = AZ_BANK_TO_OFFSET(sch->R177240); // пересчитываем в адреса
				begin_adress2 = AZ_BANK_TO_OFFSET(sch->R177242); // пересчитываем в адреса
				length_in_words1 = roll_size;
				length_in_words2 = roll_size;
			}
		} // автоопределение

		TRACE("simple_save_memory_to_file> addr=%u  len=%u  filename='%s'\n\r", begin_adress0, length_in_words0, screen_filename->GetString());
		//-----------------------
		bool bRes = file_screen.PutF(m_pAZMainMemory + begin_adress0, length_in_words0 * 2);

		//-----------------------
		if (bRes && length_in_words1 > 0) // это слоеный режим
		{
			//TRACE("simple_save_memory_to_file> puff mode on - save\n\r");
			bRes = file_screen.PutF(m_pAZMainMemory + begin_adress1, length_in_words1 * 2);

			if (bRes)
			{
				bRes = file_screen.PutF(m_pAZMainMemory + begin_adress2, length_in_words2 * 2);
			}
		}

		// все записано - идем на закрытие файла
		file_screen.Close();

		if (!bRes)
		{
			TRACE("simple_save_memory_to_file> error %d f_write %s \n\r", errno, screen_filename->GetString());
			screen_filename->Format(_T("ERROR %d f_write %s"), errno, screen_filename->GetString()); // вернем в буфер ошибку
		}

		return bRes;
	}

	TRACE("simple_save_memory_to_file> error %d f_open %s \n\r", errno, screen_filename->GetString());
	screen_filename->Format(_T("ERROR %d f_open %s"), errno, screen_filename->GetString()); // вернем в буфер ошибку
	//printf("simple_save_memory_to_file> ok  \n\r" );
	return false;
}


