#include "QuickDirtyXMLParser.h"
#include <stdio.h>
QuickDirtyXMLParser::QuickDirtyXMLParser() {

}
string trim(const string & str) {
	string out();
	int size = str.size();
	int eindex = size;
	int sindex = 0;
	for (int i = size-1 ; i >= 0; i-- ) {
		if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n' || str[i]=='\r') {
			eindex--;
		} else {
			break;
		}
	}
	for (int i = 0; i < size; i++ ) {
		if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n' || str[i]=='\r') {
			sindex++; // = i;	
		} else {
			break;
		}
	
	}
	if (eindex==sindex || eindex < sindex) {
		return "";
	}
	return str.substr(sindex,eindex-(sindex));
}
bool matches(string & tag,string & in, int start,int tagsize,int insize) {
	if (start+tagsize > insize) {
		return false;
	}
	for (int i = 0; i < tagsize ; i++ ) {
		if (!(in[start + i] == tag[i])) {
			return false;
		}
	}
	return true;
}

//Also have to deal with Upper Level Stuff
//<COMPOUND><COMPOUND/><COMPOUND/><SCALAR></COMPOUND>
//Alg:
//	first name we find quickly find next occurance. Parse inbetween, set
//	value or recurse. Then back to top level add to childlist carry on to
//	next and do the same thing

void parseXML(TreeNode * parentNode,string & xml, int current, int end) {
	bool hasXML = false;
	for (int i = current; i < end; i++) { //if current >  end then we will have a scalar
		if (xml[i] == '<' || xml[i] == '>') {
			hasXML = true;
			break;
		}
	}
	if (!hasXML) { // SCALAR
		int size = end - current;
		if (size < 0) { 
			parentNode->value = "";
		} else {
			parentNode->value = trim(xml.substr(current,end-current)); //It's SCALAR we are done!
		}
		return;
	}
	vector<TreeNode *> * children = new vector<TreeNode*>();
	string ttag = ""; //We don't quite moving til we reach the other tag end
	bool readingTag = false; //Are we inside < >
	bool parent     = false;
	bool startTag   = false; //Are we reading a startTag?
	bool endTag     = false;
	int tagStart = 0;
	int tagEnd = 0;
	int contentStart = 0;
	int contentEnd = 0;
	for (int i = current ; i < end; i++) {
		switch (xml[i]) {
			case '<': {
				readingTag = true; //start reading tag
				contentEnd = i-1;
				break;
			};
			case '>': {
				readingTag = false; //we're done reading the tag
				if (startTag) {
					tagEnd = i - 1;
					contentStart = i + 1; //this spot is start of content
					ttag = xml.substr(tagStart,tagEnd-tagStart+1); //remember the tag;
					parent = true;	//we are now in parent mode
					startTag = false;
				} else if (endTag) {
					tagEnd = i - 1;
					if (ttag == xml.substr(tagStart,tagEnd-tagStart+1)) {
						parent = false;
						//Now everything between contentStart
						//and contentEnd is stuff we want to
						//parse
						TreeNode * node = new TreeNode(ttag,"");
						parseXML(node,xml,contentStart,contentEnd+1);
						children->push_back(node);
						endTag = false;
					} else {
						endTag = false;
						//it was inside
					}
				} else {
					//intermediate tag, just ignore
				}
				break;
			};
			case '/':  {
				if (readingTag) { //</
					if (startTag) {
						tagEnd = i-1;
						startTag = false;
						parent = false;
						children->push_back(new TreeNode(xml.substr(tagStart,tagEnd-tagStart+1),""));
						//singleton! <stuff/>
					} else {
						tagStart = i+1;
						endTag  = true;
						//we'ved started to read an end tag  "stuff</_"
					}
				}
				break;
			}; 
			default: {
				if (readingTag && !parent) {
					parent = true;
					startTag = true;
					tagStart = i;
				}
			};
		}
	}
	if (parentNode->children!=NULL) {
		parentNode->clearChildren();
		delete parentNode->children;
	}
	parentNode->children = children;
}
TreeNode * QuickDirtyXMLParser::parseString(string & xml) {
	TreeNode * root = new TreeNode("root","");
	parseXML(root,xml,0,xml.size());
	return root;
}
/*
 *	<top>
 *		<inner1><inner12>inner12</inner12></inner1>
 *		<inner2><inner22/></inner2>
 *		<inner3>
 *			<inner32/>
 *			<inner33>
 *				<inner34>inner34</inner34>
 *			</inner33>
 *		</inner3>
 *	</top>
 *	Should get
 *	(top,"")
 *		(inner1,"")
 *			(inner12,"inner12")
 *		(inner2,"")
 *			(inner22,"")
 *		(inner3,"")
 *			(inner32,"") (inner33,"")
 *					(inner34,"inner34")
 * */

string * traverseTree(TreeNode * node) {
	if (node == NULL) {
		return new string("");
	}
	string * work = new string(node->getValue());
	vector<TreeNode*> * children = node->getChildren();
	if (children!=NULL) {
		vector<TreeNode*>::iterator iter;
		for (iter = children->begin(); iter < children->end(); iter++) {
			string * result = traverseTree(*iter);
			(*work) += (*result);
			delete result; //is this the right place to do it?
		}
	}
	return work;
}
int mainTest() {
	string xml []  = {string("<top> <inner1><inner12>inner12 </inner12></inner1> <inner2><inner22/></inner2> <inner3> <inner32/> <inner33> <inner34>inner34</inner34> </inner33> </inner3> </top>"),
	string("<top> <inner1>  <inner12>  inner12 </inner12></inner1> <inner2><inner22/></inner2> <inner3> <inner32/> <inner33> <inner34>   inner34   </inner34> </inner33> </inner3> </top>"),
	string("<top> <inner1>  <inner12>inner12</inner12></inner1> <inner2><inner22/></inner2> <inner3> <inner32/> <inner33> <inner34>inner34</inner34> </inner33> </inner3> <inner4></inner4><inner5/></top>")
	};
	string expect = "inner12inner34";
	string work = "";
	QuickDirtyXMLParser p = QuickDirtyXMLParser();
	for (int i = 0 ; i < 3; i++) {
		TreeNode * node = p.parseString(xml[i]);
		work = *traverseTree(node);
		if (expect == work) {
			cout << "Excellent Test "<< (1+i) <<" Worked Fine\n";	
		} else {
			cout << "Test Failed! expected[" << expect << "] received [" << work << "]\n";
		}
		try {
			string value = node->getChild("top")->getChild("inner1")->getChild("inner12")->getValue();
			if (value == "inner12") {
				cout << "Test Succeeded!\n";
			} else {
				cout << "Test Failed inner12 != " << value << " !\n";
			}
		} catch (string * err) {
			cout << "Test Failed! top inner1 inner12 not found!\n";
		}
		try {
			string value = node->getChild("top")->getChild("inner1")->getChild("inner13")->getValue();
			cout << "Test Failed inner13 found!\n";
		} catch (string * err) {
			cout << "Test Succeeded! inner13 not found [this is good]!\n";
		}
	}
	return 0;
}

