#include "pch.h"
#include "ErrorManager.h"
#include "Globals.h"
#include "Listing.h"

#pragma warning(disable:4996)

BKTurboAsm_Error errors[] =
{
	{ ERROR_100 + 100, L"Нет места для меток." },
	{ ERROR_101 + 100, L"Псевдокоманда .LA должна быть первой в тексте." },
	{ ERROR_102 + 100, L"Ошибка длины или направления перехода в команде SOB." },
	{ ERROR_103 + 100, L"Недопустимый символ в строке." },
	{ ERROR_104 + 100, L"Отсутствие метки." },
	{ ERROR_105 + 100, L"Ошибка или отсутствие числового аргумента." },
	{ ERROR_106 + 100, L"Неправильная псевдокоманда." },
	{ ERROR_107 + 100, L"Неправильная ассемблерная инструкция." },
	{ ERROR_108 + 100, L"Отсутствует символ после \'." },
	{ ERROR_109 + 100, L"Отсутствуют или недостаточно символов после \"." },
	{ ERROR_110 + 100, L"Ошибка длины перехода по оператору ветвления." },
	{ ERROR_111 + 100, L"Недопустимое использование имени метки." },
	{ ERROR_112 + 100, L"Ошибка аргумента MARK." },
	{ ERROR_113 + 100, L"Ошибка в имени регистра." },
	{ ERROR_114 + 100, L"Ошибка в псевдокоманде." },
	{ ERROR_115 + 100, L"Ошибка в команде." },
	{ ERROR_116 + 100, L"Метка уже определена ранее." },
	{ ERROR_117 + 100, L"Аргумент .BLKB слишком велик." },
	{ ERROR_118 + 100, L"Аргумент .BLKW слишком велик." },
	{ ERROR_119 + 100, L"Аргумент .ORG слишком велик." },
	{ ERROR_120 + 100, L"Нечётный адрес команды." },
	{ ERROR_121 + 100, L"Отсутствует .END" },
	{ ERROR_122 + 100, L"Неопределённая метка в непосредственном выражении." },
	{ ERROR_123 + 100, L"Любые метки в выражении запрещены." },
	{ ERROR_124 + 100, L"Отсутствует переход у команды SOB." },
	{ ERROR_125 + 100, L"Ошибка аргумента TRAP." },
	{ ERROR_126 + 100, L"Ошибка аргумента EMT." },
	{ ERROR_127 + 100, L"Ошибка или неверный метод адресации." },
	{ ERROR_128 + 100, L"Отсутствует второй операнд." },
	{ ERROR_129 + 100, L"Переполнение байтового аргумента." },
	{ ERROR_130 + 100, L"Неожиданный конец строкового аргумента." },
	{ ERROR_131 + 100, L"Ошибка в числе с плавающей точкой." },
	{ ERROR_132 + 100, L"Невозможно открыть файл include." },
	{ ERROR_133 + 100, L"Ошибка в аргументах псевдокоманды." },
	{ ERROR_134 + 100, L"Переполнение словного аргумента." },
	{ ERROR_135 + 100, L"Ошибка в числовом аргументе." },
};

int IsError()
{
	return g_GlobalParameters.nError;
}

/*
вывод сообщения об ошибке.
n - номер ошибки
boutstr true - вывести строку, в которой случилась ошибка,
*/
wchar_t errbuf[65536] = { 0 };
wchar_t errbuf2[65536] = { 0 };
void OutError(ERROR_NUMBER n, bool bOutStr, int nAddr)
{
	FILE *errf = _wfopen(L"_errors.txt", L"a");
	/*
	Тут в общем такая ситуация:
	nAddr введён только для того, чтобы правильно отслеживать ошибку длины перехода
	по ветвлению вперёд.
	Во всех случаях nAddr == -1 == значение по умолчанию.
	и только в одном единственном случае возникновения ошибки перехода по ветвлению вперёд
	nAddr - это адрес команды, которая вызвала ошибку 110

	!!! Если возникнет ещё какая нибудь такая ситуация, придётся всё переделывать.

	*/
	auto pll = g_Listing.end() - 1;

	if (nAddr == -1)
	{
		nAddr = g_GlobalParameters.nPC;
	}
	else if (n == ERROR_110)
	{
		// нужно теперь найти, в какое место вставить текст ошибки в листинге
		bool bEx = false;

		for (auto ll = g_Listing.begin(); ll != g_Listing.end(); ++ll)
		{
			for (auto &lct : ll->vCMD)
			{
				if (lct.nPC == nAddr && lct.LT == ListType::LT_INSTRUCTION)
				{
					pll = ll;
					bEx = true;
					break;
				}
			}

			if (bEx)
			{
				break;
			}
		}
	}

	// и приятный бонус. теперь и тут всё правильно отображается для ошибки 110 по переходу вперёд.
	_swprintf(errbuf2, L"Error %3d: %s\n", errors[n].num, errors[n].str.c_str());
	_swprintf(errbuf, L"Line %d (Addr: %07o)", pll->nLineNum, CorrectAddress(nAddr));
	pll->errors.emplace_back(std::wstring(errbuf2)); // добавляем в листинг ошибку
	wprintf(L"%s - %s", errbuf, errbuf2);

	if (errf)
	{
		fwprintf(errf, L"%s :: %s - %s", g_pReader->GetFileName().c_str(), errbuf, errbuf2);
	}

#if (DEBUG_LABEL_MANAGER)
	// /-----------------------debug---------------------------
	fwprintf(dbgF, L"%s", errbuf);
	// /-----------------------debug---------------------------
#endif

	// если нужно - ещё и строку покажем, где ошибка
	if (bOutStr)
	{
		wprintf(L"%s\n", pll->line.c_str());

		if (errf)
		{
			fwprintf(errf, L"%s\n", pll->line.c_str());
		}

#if (DEBUG_LABEL_MANAGER)
		// /-----------------------debug---------------------------
		fwprintf(dbgF, L"%s\n", pll->line.c_str());
		// /-----------------------debug---------------------------
#endif
	}

	if (errf)
	{
		fclose(errf);
	}

	g_GlobalParameters.nError++;
}

