reflection

                Never    
C/C++
       
#include "loader.h"

#include "../ReflectionDatabase/reflectiondatabase.h"
#include "../Core/plugin.h"
#include "../Utils/utils.h"

void Loader::ParseClassHeader(std::vector<std::string>* n)
{
	n->push_back("//Generated by reflect parser");
	n->push_back("");

	n->push_back("#pragma once");
	n->push_back("");

	n->push_back("#include \"rttr/registration.h\"");
	n->push_back("#include \"../../ReflectionDatabase/reflectiondatabase.h\"");
	n->push_back("#include \"../../Core/plugin.h\"");
	n->push_back("#include <iostream>");
	n->push_back("");

	n->push_back("#define BODY \\");
	n->push_back("void RegisterReflection() \\");
	n->push_back("{ \\");
	n->push_back("std::cout << \"Creating reflection for: " + m_ClassName + "\" << std::endl;\\");

	std::string dir = m_Directory;

	replaceAll(dir, "\\", "/");	

	n->push_back("PluginAPI plugin(\"D:/Projects/C++/N'gine/Debug/ReflectionDatabase.dll\"); \\");
	n->push_back("ReflectionDatabase* reflection = plugin.Init<ReflectionDatabase>(); \\");

	for (int i = 0; i < m_ReflectionDependency.size(); i++)
	{
		if (dir + "/" + m_File == m_ReflectionDependency[i])
		{
			continue;
		}

		n->push_back("reflection->AddFile(\"" + dir + "/" + m_File + "\", \"" + m_ReflectionDependency[i] + "\"); \\");
	}

	n->push_back("rttr::registration::class_<" + m_ClassName + ">(\"" + m_ClassName + "\")\\");

	if (m_ClassMeta.size() > 0)
	{
		n->push_back("(\\");
		for (unsigned int i = 0; i < m_ClassMeta.size(); i++)
		{
			n->push_back("rttr::metadata(" + m_ClassMeta[i].m_Type + ", " + m_ClassMeta[i].m_Value + ")" + (i < m_ClassMeta.size() - 1 ? ",\\" : "\\"));
		}
		n->push_back(")\\");
	}

	for (ClassConstructor cons : m_Constructors)
	{
		std::string constructor = ".constructor<";

		unsigned int counter = 0;

		for (Argument arg : cons.m_Constructors)
		{
			for (std::string args : arg.m_ArgumentType)
			{
				constructor.append(" " + args);
			}

			counter++;

			if (counter < cons.m_Constructors.size())
			{
				constructor.append(",");
			}
		}

		constructor += ">()\\";

		n->push_back(constructor);
	}

	for (ClassArgument arg : m_ClassValues)
	{
		n->push_back(".property(\"" + arg.m_ArgumentName + "\", &" + m_ClassName + "::" + arg.m_ArgumentName + ")\\");
		if (arg.m_Meta.size() > 0)
		{
			n->push_back("(\\");
			for (unsigned int i = 0; i < arg.m_Meta.size(); i++)
			{
				n->push_back("rttr::metadata(" + arg.m_Meta[i].m_Type + ", " + arg.m_Meta[i].m_Value + ")" + (i < arg.m_Meta.size() - 1 ? ",\\" : "\\"));
			}
			n->push_back(")\\");
		}
	}

	for (Method method : m_ClassMethods)
	{
		n->push_back(".method(\"" + method.m_MethodName + "\", &" + m_ClassName + "::" + method.m_MethodName + ")\\");
		if (method.m_Meta.size() > 0)
		{
			n->push_back("(\\");
			for (unsigned int i = 0; i < method.m_Meta.size(); i++)
			{
				n->push_back("rttr::metadata(" + method.m_Meta[i].m_Type + ", " + method.m_Meta[i].m_Value + ")" + (i < method.m_Meta.size() - 1 ? ",\\" : "\\"));
			}
			n->push_back(")\\");
		}
	}

	n->push_back(";\\");
	n->push_back("}");

	/*
	n->push_back("//Generated by reflect parser");
	n->push_back("");

	n->push_back("#pragma once");
	n->push_back("");

	n->push_back("namespace SteelEngine");
	n->push_back("{");
	{
		n->push_back("\tnamespace Reflection");
		n->push_back("\t{");
		{
			n->push_back("\t\tclass " + m_ClassName + "_Reflected");
			n->push_back("\t\t{");
			{
				n->push_back("\t\tprivate:");
				n->push_back("\t\t");
				n->push_back("\t\tpublic:");
				n->push_back("\t\t\t" + m_ClassName + "_Reflected();");
				n->push_back("\t\t\t~" + m_ClassName + "_Reflected();");
				n->push_back("\t\t");
				n->push_back("\t\t\tstatic void Create();");
			}
			n->push_back("\t\t};");
		}
		n->push_back("\t}");
	}
	n->push_back("}");
	*/
}

void Loader::ParseClassSource(std::vector<std::string>* n)
{
	/*
	n->push_back("//Generated by reflect parser");
	n->push_back("");

	n->push_back("#include \"" + m_GeneratedFilesDirectory + "/" + m_File + ".Generated.h\"");
	n->push_back("#include \"" + m_Directory + "/" + m_File + ".h\"");

	n->push_back("#include \"rttr/registration.h\"");
	n->push_back("#include <iostream>");

	n->push_back("");

	n->push_back("namespace SteelEngine");
	n->push_back("{");
	{
		n->push_back("\tnamespace Reflection");
		n->push_back("\t{");
		{
			n->push_back("\t\t" + m_ClassName + "_Reflected" + "::" + m_ClassName + "_Reflected" + "()");
			n->push_back("\t\t{");
			{
				
			}
			n->push_back("\t\t}");

			n->push_back("");

			n->push_back("\t\t" + m_ClassName + "_Reflected" + "::~" + m_ClassName + "_Reflected" + "()");
			n->push_back("\t\t{");
			{

			}
			n->push_back("\t\t}");
			n->push_back("\t\t");

			/////////////////////

			n->push_back("\t\tvoid " + m_ClassName + "_Reflected::Create()");
			n->push_back("\t\t{");
			{
				n->push_back("\t\t\trttr::registration::class_<" + m_ClassName + ">(\"" + m_ClassName + "\")");

				if (m_ClassMeta.size() > 0)
				{
					n->push_back("\t\t\t\t(");
					for (unsigned int i = 0; i < m_ClassMeta.size(); i++)
					{
						n->push_back("\t\t\t\t\trttr::metadata(" + m_ClassMeta[i].m_Type + ", " + m_ClassMeta[i].m_Value + ")" + (i < m_ClassMeta.size() - 1 ? "," : ""));
					}
					n->push_back("\t\t\t\t)");
				}

				for (ClassConstructor cons : m_Constructors)
				{
					std::string constructor = "\t\t\t\t.constructor<";

					unsigned int counter = 0;

					for (Argument arg : cons.m_Constructors)
					{
						for (std::string args : arg.m_ArgumentType)
						{
							constructor.append(" " + args);
						}

						counter++;

						if (counter < cons.m_Constructors.size())
						{
							constructor.append(",");
						}
					}

					constructor += ">()";

					n->push_back(constructor);
				}

				for (ClassArgument arg : m_ClassValues)
				{
					n->push_back("\t\t\t\t.property(\"" + arg.m_ArgumentName + "\", &" + m_ClassName + "::" + arg.m_ArgumentName + ")");
					if (arg.m_Meta.size() > 0)
					{
						n->push_back("\t(");
						for (unsigned int i = 0; i < arg.m_Meta.size(); i++)
						{
							n->push_back("\t\t\t\t\trttr::metadata(" + arg.m_Meta[i].m_Type + ", " + arg.m_Meta[i].m_Value + ")" + (i < arg.m_Meta.size() - 1 ? "," : ""));
						}
						n->push_back("\t\t\t\t)");
					}
				}

				for (Method method : m_ClassMethods)
				{
					n->push_back("\t\t\t\t.method(\"" + method.m_MethodName + "\", &" + m_ClassName + "::" + method.m_MethodName + ")");
					if (method.m_Meta.size() > 0)
					{
						n->push_back("\t\t\t\t(");
						for (unsigned int i = 0; i < method.m_Meta.size(); i++)
						{
							n->push_back("\t\t\t\t\trttr::metadata(" + method.m_Meta[i].m_Type + ", " + method.m_Meta[i].m_Value + ")" + (i < method.m_Meta.size() - 1 ? "," : ""));
						}
						n->push_back("\t\t\t\t)");
					}
				}

				n->push_back("\t\t\t\t;");

				//n->push_back("\t\t\tstd::cout << \"Generated reflect module: " + m_ClassName + "\" << std::endl;");
			}
			n->push_back("\t\t}");

			/////////////////////
		}
		n->push_back("\t}");
	}
	n->push_back("}");
	*/
}

std::vector<Loader::Meta> Loader::ParseMeta(const std::string& meta)
{
	std::vector<Meta> result;
	std::vector<std::string> metas = split(meta, ',');

	for (unsigned int i = 0; i < metas.size(); i++)
	{
		if (metas[i].find("(") != std::string::npos)
		{
			if (metas[i].find(")") != std::string::npos)
			{
				continue;
			}
			else
			{
				again:
				for (unsigned int j = i + 1; j < metas.size(); j++)
				{
					if (metas[j].find(")") != std::string::npos)
					{
						metas[i].append(", ").append(metas[j]);

						metas.erase(metas.begin() + j);

						j--;
					}
					else
					{
						metas[i].append(", ").append(metas[j]);

						metas.erase(metas.begin() + j);

						goto again;
					}
				}
			}
		}
		else
		{
			if (metas[i].find(")") != std::string::npos)
			{
				metas[i - 1].append(", ").append(metas[i]);

				metas.erase(metas.begin() + i);
			}
		}
	}

	for (std::string a : metas)
	{
		std::vector<std::string> b = split(a, '=');

		for (unsigned int i = 0; i < b.size(); i++)
		{
			b[i].erase(std::remove(b[i].begin(), b[i].end(), ' '), b[i].end());
		}

		result.push_back(Meta{ b[0], b[1] });
	}

	return result;
}

Loader::Loader(const std::string& directory, const std::string& generatedDir, const std::string& file) :
	m_File(file),
	m_Directory(directory),
	m_GeneratedFilesDirectory(generatedDir)
{
	m_ConstructorID = -1;
}

Loader::~Loader()
{

}

void Loader::Load()
{
	std::ifstream headerFile(m_Directory + "/" + m_File + ".h");

	std::string line;

	while (std::getline(headerFile, line))
	{
		m_Loaded.m_Header.push_back(line);
	}

	headerFile.close();

	std::ifstream sourceFile(m_Directory + "/" + m_File + ".cpp");

	while (std::getline(sourceFile, line))
	{
		m_Loaded.m_Source.push_back(line);
	}

	sourceFile.close();
}

bool Loader::Parse()
{
	unsigned int lineID = 0;
	unsigned int previousLine = 0;
	bool reflect = false;

	PluginAPI plugin("D:/Projects/C++/N'gine/Debug/ReflectionDatabase.dll");

	ReflectionDatabase* reflection = plugin.Init<ReflectionDatabase>();

	for (std::string line : m_Loaded.m_Source)
	{
		if (line.find("SE_TYPE") != std::string::npos)
		{
			std::string current = line;

			size_t pos = current.find("SE_TYPE(");

			current.erase(current.begin(), current.begin() + pos);
			current.erase(current.begin(), current.begin() + strlen("SE_TYPE(\""));
			current.erase(current.end() - 3, current.end());

			std::cout << "Class: " << current << std::endl;
			std::cout << m_Directory + "/" + m_File << std::endl;

			std::string file1 = m_Directory + "/" + m_File;
			std::string file2 = m_Directory + "/" + current;

			replaceAll(file1, "\\", "/");
			replaceAll(file2, "\\", "/");

			reflection->AddFile(file1, file2);

			std::transform(file2.begin(), file2.end(), file2.begin(), ::tolower);

			m_ReflectionDependency.push_back(file2);
		}
	}

	for (std::string line : m_Loaded.m_Header)
	{
		if (line.find("SE_CLASS") != std::string::npos)
		{
			std::string current = line;

			current.erase(current.begin(), current.begin() + strlen("SE_CLASS("));
			current.erase(current.end() - 1, current.end());

			m_ClassMeta = ParseMeta(current);
			previousLine = lineID + 1;
			m_ClassName = m_Loaded.m_Header[lineID + 1];

			std::vector<std::string> names = split(m_ClassName, ' ');

			m_ClassName = names[1];

			reflect = true;
		}
		else if (line.find("SE_VALUE") != std::string::npos)
		{
			std::string currentMeta = m_Loaded.m_Header[lineID];

			currentMeta.erase(std::remove(currentMeta.begin(), currentMeta.end(), '\t'), currentMeta.end());
			currentMeta.erase(currentMeta.begin(), currentMeta.begin() + strlen("SE_VALUE("));
			currentMeta.erase(currentMeta.end() - 1, currentMeta.end());

			std::string current = m_Loaded.m_Header[lineID + 1];

			current.erase(std::remove(current.begin(), current.end(), '\t'), current.end());
			current.erase(current.end() - 1, current.end());
			std::vector<std::string> allArgs = split(current, ' ');

			ClassArgument arg(allArgs[allArgs.size() - 1]);

			arg.m_Meta = ParseMeta(currentMeta);

			allArgs.erase(allArgs.end() - 1);

			for (std::string a : allArgs)
			{
				arg.m_ArgumentType.push_back(a);
			}

			m_ClassValues.push_back(arg);
		}
		else if (line.find("SE_METHOD") != std::string::npos)
		{
			std::string currentMeta = m_Loaded.m_Header[lineID];

			currentMeta.erase(std::remove(currentMeta.begin(), currentMeta.end(), '\t'), currentMeta.end());
			currentMeta.erase(currentMeta.begin(), currentMeta.begin() + strlen("SE_METHOD("));
			currentMeta.erase(currentMeta.end() - 1, currentMeta.end());

			std::string current = m_Loaded.m_Header[lineID + 1];

			current.erase(std::remove(current.begin(), current.end(), '\t'), current.end());
			current.erase(current.end() - 1, current.end());
			std::vector<std::string> allArgs = split(current, '(');
			std::vector<std::string> type = split(allArgs[0], ' ');
			std::vector<std::string> args = split(allArgs[1], ',');

			std::string funcName = type[type.size() - 1];

			type.erase(type.end() - 1);

			Method method(funcName);

			method.m_Meta = ParseMeta(currentMeta);

			for (std::string a : type)
			{
				method.m_ReturnType.push_back(a);
			}

			if (args.size() > 1)
			{
				for (std::string a : args)
				{
					std::string current = a;

					current.erase(std::remove(current.begin(), current.end(), ')'), current.end());

					std::vector<std::string> b = split(current, ' ');

					Argument arg(b[b.size() - 1]);

					b.erase(b.end() - 1);

					for (std::string c : b)
					{
						if (c != "")
						{
							arg.m_ArgumentType.push_back(c);
						}
					}

					method.m_Arguments.push_back(arg);
				}
			}

			m_ClassMethods.push_back(method);
		}

		lineID++;
	}

	if (!reflect)
	{
		return false;
	}

	lineID = 0;

	for (std::string line : m_Loaded.m_Header)
	{
		if (line.find(m_ClassName) != std::string::npos && lineID > previousLine)
		{
			if (line.find("~" + m_ClassName) != std::string::npos)
			{

			}
			else
			{
				std::string constructorLine = line;

				constructorLine.erase(std::remove(constructorLine.begin(), constructorLine.end(), '\t'), constructorLine.end());
				constructorLine.erase(constructorLine.begin(), constructorLine.begin() + strlen(m_ClassName.c_str()));

				constructorLine.erase(constructorLine.begin(), constructorLine.begin() + 1);
				constructorLine.erase(constructorLine.end() - 2, constructorLine.end());

				std::vector<std::string> allArgs = split(constructorLine, ',');
				std::vector<Argument> args;

				for (std::string arg : allArgs)
				{
					std::vector<std::string> splitted = split(arg, ' ');

					Argument argument(splitted[splitted.size() - 1]);

					splitted.erase(splitted.end() - 1);

					for (std::string bigArg : splitted)
					{
						if (bigArg != "")
						{
							argument.m_ArgumentType.push_back(bigArg);
						}
					}

					args.push_back(argument);
				}

				m_Constructors.push_back(ClassConstructor{ m_ConstructorID++, args });
			}
		}

		lineID++;
	}

	ParseClassHeader(&m_Parsed.m_Header);
	ParseClassSource(&m_Parsed.m_Source);

	return reflect;
}

void Loader::CreateReflectedFiles()
{
	std::ofstream headerFile(m_GeneratedFilesDirectory + "/" + m_File + ".Generated" + ".h");

	for (std::string line : m_Parsed.m_Header)
	{
		headerFile << line << "\n";
	}

	headerFile.close();

	std::ofstream sourceFile(m_GeneratedFilesDirectory + "/" + m_File + ".Generated" + ".cpp");

	for (std::string line : m_Parsed.m_Source)
	{
		sourceFile << line << "\n";
	}

	sourceFile.close();
}