#include "tinyxml.h"

#include "MPQDBCFieldObject.h"

CMPQDBCFieldManager::CMPQDBCFieldManager()
{
}

CMPQDBCFieldManager::~CMPQDBCFieldManager()
{
	Destory();
}

void CMPQDBCFieldManager::Destory()
{
	TDBCMap::iterator it = _mapDBC.begin();
	while(it != _mapDBC.end())
	{
		TFieldMap::iterator i = it->second.begin();
		while(i != it->second.end())
		{
			delete i->second;
			it->second.erase(i++);
		}
		_mapDBC.erase(it ++);
	}
}

int CMPQDBCFieldManager::Load(const std::string &xml, bool reload)
{
	if(reload)
	{
		Destory();
	}
	return ParseXML(xml);		
}

const CMPQDBCFieldManager::TFieldMap* CMPQDBCFieldManager::FindDBCFields(const std::string& dbc) const
{
	TDBCMap::const_iterator it = _mapDBC.find(dbc);
	if(it == _mapDBC.end())
		return NULL;
	return &it->second;
}

int CMPQDBCFieldManager::ParseXML(const std::string &xml)
{
	TiXmlDocument doc;
	if(!doc.LoadFile(xml.c_str()))
		return -1;

	std::string name;

	const TiXmlElement* root = doc.RootElement();
	if(root->ValueStr() != "DBCFile")
		return -1;
	const TiXmlElement* file = root->FirstChildElement();
	while(file != NULL)
	{
		//File Attribute
		name.clear();
		const TiXmlAttribute* attr = file->FirstAttribute();
		while(attr != NULL)
		{
			if(attr->NameTStr() == "name")
				name = attr->ValueStr();
			attr = attr->Next();
		}
		if(!name.empty())
		{
			TDBCMap::iterator it = _mapDBC.insert(std::make_pair(name, TFieldMap())).first;
			if(it == _mapDBC.end())
				return -1;

			const TiXmlElement* fields = file->FirstChildElement("Fields");
			if(fields != NULL)
			{
				const TiXmlElement * field = fields->FirstChildElement("Field");
				while(field != NULL)
				{
					FieldAttr_t data;
					data.m_iPos = -1;
					data.m_strType.clear();
					data.m_strTitle = field->GetText();
					attr = field->FirstAttribute();
					while(attr != NULL)
					{
						if(attr->NameTStr() == "position")
							data.m_iPos = attr->IntValue();
						else if(attr->NameTStr() == "type")
							data.m_strType = attr->ValueStr();
						else if(attr->NameTStr() == "size")
							data.m_iSize = attr->IntValue();
						else if(attr->NameTStr() == "refdbc")
							data.m_strRefDBC = attr->ValueStr();
						else if(attr->NameTStr() == "reffield")
							data.m_iRefPos = attr->IntValue();
						else if(attr->NameTStr() == "number")
							data.m_iNumber = attr->IntValue();

						attr = attr->Next();
					}
					DBCField::CField* dbcfield = MakeDBCField(data);
					if(dbcfield != NULL)
					{
						TFieldMap::iterator i = it->second.find(data.m_iPos);
						if(i == it->second.end())
						{
							it->second.insert(std::make_pair(dbcfield->m_iPos, dbcfield));
						}
						else
						{
							delete i->second;
							i->second = dbcfield;
						}
					}

					field = field->NextSiblingElement();
				}
			}
		}
		file = file->NextSiblingElement();
	}

	return 0;
}

DBCField::CField* CMPQDBCFieldManager::MakeDBCField(const CMPQDBCFieldManager::FieldAttr_t &attr) const
{
	if(attr.m_iPos == -1 || attr.m_strType.empty())
		return NULL;
	if(attr.m_strType == "integer")
		return new DBCField::CIntegerField(attr.m_strTitle, attr.m_iPos, attr.m_iSize);
	else if(attr.m_strType == "string")
		return new DBCField::CStringField(attr.m_strTitle, attr.m_iPos, attr.m_iSize);
	return NULL;
}