#include "../Include/XMLParser.h"



XMLParser::XMLParser()
{
}

void XMLParser::sub_buffer(char *&buffer, char match_char)
{
	while (*buffer != match_char)
	{
		++buffer;
	}
}

void XMLParser::clean_string(std::string &string_buffer)
{
	int n = 0;
	for (int i = 0; i< string_buffer.length(); i++) {
		if (string_buffer[i] == '\t' || string_buffer[i] == '\n' || string_buffer[i] == '\r') {
			n++;
		}
		else {
			string_buffer[i - n] = string_buffer[i];
		}
	}
	string_buffer.resize(string_buffer.length() - n);
}

std::string XMLParser::retrieve_string(char *buffer, int size)
{
	return std::string(buffer).substr(0, size);
}

std::string XMLParser::retrieve_node_content(char *&buffer)
{
	char *tmp_buffer = buffer;
	sub_buffer(buffer, '<');
	return trim(remove_newlines(retrieve_string(tmp_buffer, buffer - tmp_buffer)), " ");
}

void XMLParser::retrieve_child(char *&buffer, XMLParser::nodetype *&childnode)
{
	nodetype *firstnode;
	nodetype *tempchildnode;
	
	while (true)
	{
		if (*buffer == 0)
			break;

		// Parse and append new child
		if (*buffer == '<')
		{
			++buffer;
			if (*buffer != '/' && *buffer != '?' && *buffer != '!' && *buffer != ' ')
			{
				tempchildnode = new XMLParser::nodetype();
				delete tempchildnode;
				tempchildnode = retrieve_element(buffer);
				if (childnode == 0) { //update2
					childnode = tempchildnode;
					firstnode = tempchildnode;
				}
				else {
					firstnode->sibling = tempchildnode;
					firstnode = tempchildnode;
				}
			}
		}
		else
		{
			++buffer;
		}
	}
	tempchildnode->sibling = 0; //update2
}

std::string XMLParser::remove_newlines(string str)
{
	string::size_type pos = 0;
	while ((pos = str.find("\r\n", pos)) != string::npos)
	{
		str.erase(pos, 2);
	}
	return str;
}

XMLParser::attributetype* XMLParser::parse_attribute(std::string str_buffer)
{
	XMLParser::attributetype *firstattr;
	XMLParser::attributetype *attributes = new attributetype;
	delete attributes;
	attributes = 0; //update

	string tmp_str_buffer;
	string attribute_name;
	string attribute_value;

	int attr_pos = 0;
	int value_start_pos = 0;
	int value_end_pos = 0;
	int end_pos = 0;
	
	clean_string(str_buffer);

	while (true)
	{
		attr_pos = str_buffer.find('=');
		if (attr_pos == std::string::npos)
			break;

		attribute_name = trim(str_buffer.substr(0, attr_pos), " ");
		//cout << "attrname=" << attribute_name << endl;

		value_start_pos = str_buffer.find('"');
		value_end_pos = str_buffer.substr(value_start_pos + 1).find('"');
		attribute_value = trim(str_buffer.substr(value_start_pos + 1, value_end_pos), " ");
		//cout << "valuename=" << attribute_value << endl;

		tempattr = new XMLParser::attributetype;
		tempattr->key = attribute_name;
		tempattr->value = attribute_value;

		if (attributes == 0) {//update2
			attributes = tempattr;
			firstattr = tempattr;
		} 
		else {
			firstattr->a = tempattr;
			firstattr = tempattr;
		}
		//Pass the rest of the string to loop.
		tmp_str_buffer = str_buffer.substr(value_start_pos + value_end_pos + 2);
		//end_pos = tmp_str_buffer.find('\n');
		str_buffer = trim(tmp_str_buffer, " ");
	}
	tempattr->a = 0; //update2
	
	return attributes;
}

XMLParser::nodetype *XMLParser::retrieve_element(char *&buffer)
{	
	if (*buffer == 0)
		return 0; //update2

	resultnode = new nodetype;
	nodetype *element_tempnode = resultnode;
	element_tempnode->child = new nodetype;
	element_tempnode->attr = new attribute;
	delete element_tempnode->child;
	delete element_tempnode->attr;

	element_tempnode->child = 0; //update	
	element_tempnode->attr = 0; //update
	
	char *tmp_buffer = buffer;

	//Retrieve node to string.
	sub_buffer(buffer, '>');
	string str_node = retrieve_string(tmp_buffer, buffer - tmp_buffer);

	//Retrieve element name.
	int pos_elementname = str_node.find(' ');
	if (pos_elementname > 0)
	{
		element_tempnode->name = remove_newlines(str_node.substr(0, pos_elementname));
		//Parse attributes.
		element_tempnode->attr = parse_attribute(str_node.substr(pos_elementname));
	}
	else
	{
		//No attributes found.
		pos_elementname = str_node.length();
		element_tempnode->name = remove_newlines(str_node.substr(0, pos_elementname));
		//tempnode->attr = NULL;
	}
	//cout << "Node name="<<tempnode->name << endl;
			
	if (buffer[-1] == '/')
	{
		//End of node.
		//tempnode->child = NULL;
	}
	else
	{			
		//Parse node content.
		while (true)
		{
			if (*buffer == 0)
				break;

			if (*buffer == '<')
			{				
				++buffer;
				if (*buffer == '/')
				{
					//End of node.
					sub_buffer(buffer, '>');
					break;
				}
				else if (*buffer != '/' && *buffer != '?' && *buffer != '!' && *buffer != ' ')
				{
					//Parse and append child node.
					buffer--;
					retrieve_child(buffer, element_tempnode->child);
				}
			}
			else if (*buffer != '/' && *buffer != '?' && *buffer != '!' && *buffer != ' ' && *buffer != '>')
			{
				//Parse node content.
				element_tempnode->text = retrieve_node_content(buffer);
				//cout << "Node Content=" << tempnode->text << endl;
			}
			else
			{
				++buffer;
			}
		}	
	}
	resultnode = element_tempnode;
	return resultnode;
}

void XMLParser::parse_xmlfile(char *buffer)
{
	nodetype *firstnode;
	nodetype *tempnode;

	while (true)
	{
		if (*buffer== 0)
			break;

		// Parse and retrieve nodes.
		if (*buffer == '<')
		{
			++buffer;
			if (*buffer != '/' && *buffer != '?' && *buffer != '!' && *buffer != ' ')
			{
				tempnode = retrieve_element(buffer);				
				
				if (p == 0) { //update2
					p = tempnode;
					firstnode = tempnode;
				}
				else {
					firstnode->sibling = tempnode;
					firstnode = tempnode;
				}
			}
		}
		else
		{
			++buffer;
		}
	}
	tempnode->sibling = 0; //update2
} 


void XMLParser::SetRootElem(string elementname)
{
	root_element_name = elementname;
}

void XMLParser::LoadXMLFile(string filename)
{
	char *buffer;
	std::ifstream xmlstream(filename, std::ifstream::binary);
	if (xmlstream) {
		xmlstream.seekg(0, xmlstream.end);
		int length = xmlstream.tellg();
		xmlstream.seekg(0, xmlstream.beg);

		buffer = new char[length];
		xmlstream.read(buffer, length);
		xmlstream.close();

		//parse xml buffer to node structure.
		parse_xmlfile(buffer);

	}
	delete[] buffer;
}

std::string XMLParser::ReadNodeKeyAsString(std::string key, std::string elementname)
{
	nodetype *element = p;
	nodetype *element_child;
	attributetype *element_attribute;
	std::string value = "";

	if (element == 0) { //update2
		cout << "\nError: XML element not found!";
	}
	else
	{
		if (key[0] == '@')
		{
			key = key.replace(0, 1, "");
		}

		if (elementname.length() > 0)
		{
			if (elementname[0] == '@')
			{
				elementname = elementname.replace(0, 1, "");
			}

			while (element != 0 && value == "") //update2
			{				
				if (element->name.compare(root_element_name) == 0)
				{
					//cout << "Main: " << element->name << "::" << elementname << endl;
					if (element->name.compare(elementname) == 0)
					{
						element_attribute = element->attr;
						if (element_attribute == 0) {//update2
							cout << "\nError: Attributes not found!";
						}
						else
						{
							while (element_attribute != 0 && value == "")//update2
							{
								if (element_attribute->key.compare(key) == 0)
								{
									//cout << "found=" << element_attribute->key << "=" << element_attribute->value << endl;
									value = element_attribute->value;
									return value;
								}
								element_attribute = element_attribute->a;
							}
						}
					}
					else
					{						
						element_child = element->child;						
						while (element_child != 0 && value == "")//update2
						{
							//cout << "Child: " << element_child->name << "::" << elementname << endl;
							if (element_child->name.compare(elementname) == 0)
							{
								//cout << "Child: " << element_child->name <<"::"<<elementname<< endl;
								element_attribute = element_child->attr;
								if (element_attribute == 0) {//update2
									cout << "\nError: Attributes not found!";
								}
								else
								{
									while (element_attribute != 0 && value == "")//update2
									{
										//cout << "attr: " << element_attribute->key << endl;
										if (element_attribute->key.compare(key) == 0)
										{
											//cout << "found child=" << element_attribute->key << "=" << element_attribute->value << endl;
											value = element_attribute->value;
											return value;
										}
										element_attribute = element_attribute->a;
									}
								}
							}
							element_child = element_child->sibling;
						}
					}
				}
				element = element->sibling;
			}

		}
		else
		{
			while (element != 0 && value == "")//update2
			{
				//cout << "Element Name=" << element->name << endl;
				if (element->name.compare(root_element_name) == 0)
				{
					element_child = element->child;
					while (element->attr != 0 && value == "")//update2
					{
						//cout << "Attr Key=" << element->attr->key << endl;
						if (element->attr->key.compare(key) == 0)
						{
							//cout << "Found=" << element->attr->key << "=" << element->attr->value << endl;
							value = element->attr->value;
							return value;
						}
						element->attr = element->attr->a;
					}

					if (value == "")
					{
						while (element_child != 0) //update2
						{
							//cout << "Child=" << element_child->name << endl;
							while (element_child->attr != 0 && value == "")//update2
							{
								//cout << "Attr Key=" << element_child->attr->key << " Expected="<<key<< endl;
								if (element_child->attr->key.compare(key) == 0)
								{
									//cout << "found2=" << element->child->attr->key << "=" << element->child->attr->value << endl;
									value = element_child->attr->value;
									return value;
								}
								element_child->attr = element_child->attr->a;
							}
							element_child = element_child->sibling;
						}
					}
				}
				element = element->sibling;
			}
		}
	}
	return value;
}

XMLParser::~XMLParser()
{
	delete resultnode;
	delete tempattr;
}
