/*
	GameEngine and Editor
	by John Ryland
	Copyright (c) 2023
*/

////////////////////////////////////////////////////////////////////////////////////
//	XML Parser

#include "XmlParser.h"
#include "XmlTokenizer.h"

struct XmlParseContext
{
	XmlTag*				rootTag;
	XmlTag*				currentTag = nullptr;
	std::string			currentAttribName;
};

static
void XmlSchemaConsumer(const XmlToken& token, XmlParseContext* ctx)
{
	if (!ctx->currentTag)
		ctx->currentTag = ctx->rootTag;

	std::string str(token.buffer, token.buffer + token.length);
	XmlTag newTag;
	switch (token.type)
	{
		case XT_Text:
			//printf(" xml text: \"%s\"\n", str.c_str());
			ctx->currentTag->text += str;
			break;
		case XT_ElementBegin:
			//printf(" xml begin: \"%s\"\n", str.c_str());
			newTag.parent = ctx->currentTag;
			newTag.tag = str;
			ctx->currentTag->children.push_back(newTag);
			ctx->currentTag = &ctx->currentTag->children.back();
			break;
		case XT_ElementEnd:
			//printf(" xml end: \"%s\"\n", str.c_str());
			ctx->currentTag = ctx->currentTag->parent;
			break;
		case XT_AttributeName:
			//printf(" xml attrib-name: \"%s\"\n", str.c_str());
			ctx->currentAttribName = str;
			break;
		case XT_AttributeValue:
			//printf(" xml attrib-value: \"%s\"\n", str.c_str());
			ctx->currentTag->attribValues.insert({ctx->currentAttribName, str });
			break;
		case XT_Comment:
			//printf(" xml comment: \"%s\"\n", str.c_str());
			break;
		case XT_Unknown:
			//printf(" xml unknown: \"%s\"\n", str.c_str());
			break;
		default:
			//printf(" xml default: \"%s\"\n", str.c_str());
			break;
	}
}

static
void XmlConsumer(const XmlToken& token, void* user)
{
	XmlSchemaConsumer(token, (XmlParseContext*)user);
}

static
void CheckReadResult(size_t result, size_t expected)
{
	if (result != expected)
	{
		printf("read result: %lu, expected: %lu\n", result, expected);
		exit(0);
	}
}

bool ParseXmlFile(const char* xmlFileName, XmlTag* root)
{
	FILE* xmlFile = fopen(xmlFileName, "r");
	if (xmlFile)
	{
		fseek(xmlFile, 0, SEEK_END);
		size_t siz = ftell(xmlFile);
		//printf("file size = %lu\n", siz);
		fseek(xmlFile, 0, SEEK_SET);
		char* xmlData = (char*)malloc(siz);
		CheckReadResult(fread(xmlData, siz, 1, xmlFile), 1);
		XmlParseContext ctx;
		ctx.rootTag = root;
		XmlTokenize(xmlData, siz, &XmlConsumer, &ctx);
		free(xmlData);
		fclose(xmlFile);
		return true;
	}
	return false;
}

