#include "pch.h"
#include "RPNChain.h"



void A_NODE::clear()
{
	type = A_TYPE::NUMBER;
	op = A_OP::NOP;
	number = 0;
	token.clear();
}

void A_NODE::Store(FILE *f) const
{
	OBJTags tag = OBJTags::OBJ_Node;
	fwrite(&tag, 1, sizeof(tag), f);
	fwrite(&type, 1, sizeof(type), f);

	switch (type)
	{
		case A_TYPE::NUMBER:
			tag = OBJTags::OBJ_NodeNMR;
			fwrite(&tag, 1, sizeof(tag), f);
			fwrite(&number, 1, sizeof(number), f);
			break;

		case A_TYPE::LOC_LABEL:
			tag = OBJTags::OBJ_NodeLBL;
			fwrite(&tag, 1, sizeof(tag), f);
			fwrite(&number, 1, sizeof(number), f);
			token.Store(f);
			break;

		case A_TYPE::LABEL:
			tag = OBJTags::OBJ_NodeLBL;
			fwrite(&tag, 1, sizeof(tag), f);
			token.Store(f);
			break;

		case A_TYPE::DOT_PC:
			tag = OBJTags::OBJ_NodeDotPC;
			fwrite(&tag, 1, sizeof(tag), f);
			fwrite(&number, 1, sizeof(number), f);
			break;

		case A_TYPE::OPERATION:
			tag = OBJTags::OBJ_NodeOP;
			fwrite(&tag, 1, sizeof(tag), f);
			fwrite(&op, 1, sizeof(op), f);
			break;
	}
}

bool A_NODE::Load(FILE *f)
{
	OBJTags tag{};
	fread(&tag, 1, sizeof(tag), f);

	if (tag == OBJTags::OBJ_Node)
	{
		size_t r = fread(&type, 1, sizeof(type), f); //читаем тип операции

		if (r == sizeof(type))
		{
			switch (type)
			{
				case A_TYPE::NUMBER:
					fread(&tag, 1, sizeof(tag), f);

					if (tag == OBJTags::OBJ_NodeNMR)
					{
						op = A_OP::NOP;
						token.clear();
						r = fread(&number, 1, sizeof(number), f);

						if (r == sizeof(number))
						{
							return true;
						}
					}

					break;

				case A_TYPE::LOC_LABEL:
					fread(&tag, 1, sizeof(tag), f);

					if (tag == OBJTags::OBJ_NodeLBL)
					{
						op = A_OP::NOP;
						r = fread(&number, 1, sizeof(number), f);

						if (r == sizeof(number))
						{
							return token.Load(f);
						}
					}

					break;

				case A_TYPE::LABEL:
					fread(&tag, 1, sizeof(tag), f);

					if (tag == OBJTags::OBJ_NodeLBL)
					{
						op = A_OP::NOP;
						number = 0;
						return token.Load(f);
					}

					break;

				case A_TYPE::DOT_PC:
					fread(&tag, 1, sizeof(tag), f);

					if (tag == OBJTags::OBJ_NodeDotPC)
					{
						op = A_OP::NOP;
						token.clear();
						r = fread(&number, 1, sizeof(number), f);

						if (r == sizeof(number))
						{
							return true;
						}
					}

					break;

				case A_TYPE::OPERATION:
					fread(&tag, 1, sizeof(tag), f);

					if (tag == OBJTags::OBJ_NodeOP)
					{
						number = 0;
						token.clear();
						r = fread(&op, 1, sizeof(op), f);

						if (r == sizeof(op))
						{
							return true;
						}
					}

					break;
			}
		}
	}

	return false;
}

void RPNChainFunc::Store(FILE *f, const RPNChain_t &rpn) // сохранение в объектный файл
{
	const auto sz = static_cast<uint32_t>(rpn.size());
	const OBJTags tag = OBJTags::OBJ_RPNChain;
	fwrite(&tag, 1, sizeof(tag), f);
	fwrite(&sz, 1, sizeof(sz), f);

	for (uint32_t i = 0; i < sz; ++i)
	{
		rpn.at(i).Store(f);
	}
}

bool RPNChainFunc::Load(FILE *f, RPNChain_t &rpn) // чтение из объектного файла
{
	OBJTags tag{};
	fread(&tag, 1, sizeof(tag), f);

	if (tag == OBJTags::OBJ_RPNChain)
	{
		rpn.clear(); //очищаем
		uint32_t sz = 0;
		const size_t r = fread(&sz, 1, sizeof(sz), f);

		if (r == sizeof(sz))
		{
			for (uint32_t i = 0; i < sz; ++i)
			{
				A_NODE node;
				const bool bRes = node.Load(f);

				if (bRes)
				{
					rpn.push_back(node);
				}
				else
				{
					return false;
				}
			}

			// если размер вектора 0 - то это не будем считать ошибкой, так записали.
			return true;
		}
	}

	return false;
}
