/*
    PIP - Platform Independent Primitives
    Code model generator
    Ivan Pelipenko peri4ko@yandex.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "metainfo.h"


void writeClassInfoMembers(Runtime & rt, const PICodeParser::Entity * e, PIString var_prefix) {
	if (var_prefix.isNotEmpty() && !var_prefix.endsWith('.')) var_prefix += ".";
	for (const PICodeParser::Entity * p: e->parents) {
		if (p->is_anonymous) continue;
		writeClassInfoMembers(rt, p, var_prefix);
	}
	for (const PICodeParser::Member & m: e->members) {
		auto type = findEntity(rt, m.type);
		if (type) {
			if (type->is_anonymous) {
				writeClassInfoMembers(rt, type, var_prefix + m.name);
				continue;
			}
		}
		rt.ts << "\tti = TypeInfo(\"" << var_prefix << m.name << "\", \"" << m.type << "\"";
		if (m.attributes != 0) {
			bool fir = true;
			rt.ts << ", ";
			if (m.attributes[PICodeParser::Const]) {
				if (fir)
					fir = false;
				else
					rt.ts << " | ";
				rt.ts << "Const";
			}
			if (m.attributes[PICodeParser::Static]) {
				if (fir)
					fir = false;
				else
					rt.ts << " | ";
				rt.ts << "Static";
			}
			if (m.attributes[PICodeParser::Mutable]) {
				if (fir)
					fir = false;
				else
					rt.ts << " | ";
				rt.ts << "Mutable";
			}
			if (m.attributes[PICodeParser::Volatile]) {
				if (fir)
					fir = false;
				else
					rt.ts << " | ";
				rt.ts << "Volatile";
			}
			if (m.attributes[PICodeParser::Inline]) {
				if (fir)
					fir = false;
				else
					rt.ts << " | ";
				rt.ts << "Inline";
			}
			if (m.attributes[PICodeParser::Virtual]) {
				if (fir)
					fir = false;
				else
					rt.ts << " | ";
				rt.ts << "Virtual";
			}
		} else {
			if (m.isBitfield()) rt.ts << ", 0";
		}
		if (m.isBitfield()) rt.ts << ", " << m.bits;
		rt.ts << ");\n";
		if (!m.meta.isEmpty()) {
			for (PICodeParser::MetaMap::const_iterator i = m.meta.begin(); i != m.meta.end(); ++i)
				rt.ts << "\tti.meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n";
		}
		rt.ts << "\tci->variables << ti;\n";
	}
}


void makeClassInfo(Runtime & rt, const PICodeParser::Entity * e) {
	rt.ts << "\n\t{\n\tClassInfo * ci = new ClassInfo();\n";
	rt.ts << "\tci->type = \"" << e->type << "\";\n";
	rt.ts << "\tci->name = \"" << e->name << "\";\n";
	// rt.ts << "\tci->is_anonymous = " << (e->is_anonymous ? "true" : "false") << ";\n";
	if (!e->meta.isEmpty()) {
		auto i = e->meta.makeIterator();
		while (i.next())
			rt.ts << "\tci->meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n";
	}
	rt.ts << "\tci_ci[ci->name] = ci;\n";
	if (e->parent_scope) {
		rt.ts << "\tpci = "
			  << "ci_ci.value(\"" << e->parent_scope->name << "\", 0);\n";
		rt.ts << "\tif (pci) pci->children_info << ci;\n";
	}
	for (const PICodeParser::Entity * p: e->parents)
		rt.ts << "\tci->parents << \"" << p->name << "\";\n";
	if (!e->members.isEmpty()) rt.ts << "\n\tTypeInfo ti;\n";
	writeClassInfoMembers(rt, e);
	PIString arg;
	bool has_fi = false;
	for (const PICodeParser::Member & m: e->functions) {
		if (e->name.findCWord(m.name) >= 0) continue;
		if (!has_fi) rt.ts << "\n\tFunctionInfo * fi;\n";
		has_fi = true;
		rt.ts << "\tci->functions.push_back(FunctionInfo()); fi = &(ci->functions.back());\n";
		rt.ts << "\tfi->name = \"" << m.name << "\";";
		rt.ts << " fi->return_type = TypeInfo(\"\", \"" << m.type << "\"";
		if (m.attributes[PICodeParser::Const] || m.attributes[PICodeParser::Static]) {
			bool fir = true;
			rt.ts << ", ";
			if (m.attributes[PICodeParser::Const]) {
				if (fir)
					fir = false;
				else
					rt.ts << " | ";
				rt.ts << "Const";
			}
			if (m.attributes[PICodeParser::Static]) {
				if (fir)
					fir = false;
				else
					rt.ts << " | ";
				rt.ts << "Static";
			}
		}
		rt.ts << ");\n";
		// piCout << "write func" << m.name;
		for (const PIString & a: m.arguments_full) {
			// piCout << "write arg" << a;
			rt.ts << "\tfi->arguments << TypeInfo(";
			arg      = a;
			bool con = false;
			arg.prepend(" ");
			if (arg.find(" const ") >= 0) {
				arg.replaceAll(" const ", " ");
				con = true;
			}
			arg.trim();
			int i = 0;
			for (i = arg.size_s() - 1; i > 0; --i)
				if (!_isCChar(arg[i]) && !(arg[i].isDigit())) break;
			rt.ts << "\"" << arg.takeRight(arg.size_s() - i - 1).trim() << "\", ";
			rt.ts << "\"" << arg.trim() << "\"";
			if (con) rt.ts << ", Const";
			rt.ts << ");\n";
		}
		if (!m.meta.isEmpty()) {
			for (PICodeParser::MetaMap::const_iterator i = m.meta.begin(); i != m.meta.end(); ++i)
				rt.ts << "\tfi->meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n";
		}
	}
	rt.ts << "\n\t}";
}
