#include "ofXML.h"

//static str for toString conversion
char toStrTmp[64];


ofXML::ofXML(){
	mainTagSet		= false;
	readingEnabled	= false;
	verbose			= true;
}

//---------------------------------------------------------
void ofXML::setVerbose(bool _verbose)
{
	verbose = _verbose;
}

//---------------------------------------------------------

void ofXML::init(string mainTag)
{
	xMainNode		= XMLNode::createXMLTopNode(mainTag.c_str());
	mainTagSet		= true;
	readingEnabled	= false;
}

//---------------------------------------------------------

void ofXML::initFromFile(string xmlFile, string mainTag)
{

	mainTagSet		= true;
	
    //open and parse the XML file:
	xMainNode=XMLNode::openFileHelper(xmlFile.c_str(),mainTag.c_str());
		
	if(!xMainNode.isError){
		//all is good we can read the file
		readingEnabled = true;
		if(verbose)printf("ofXML:  opening file %s \n", xmlFile.c_str());
	}
	else{
		//we create a node for file writing only
		if(verbose)printf("ofXML:  file not found or main tag missing - creating for file writing only\n");
		xMainNode		= XMLNode::createXMLTopNode(mainTag.c_str());
		readingEnabled	= false;
	}
}

//---------------------------------------------------------
void ofXML::saveFile(string xmlFile)
{
	if(!mainTagSet){
		if(verbose)printf("ofXML:  mainTag not set, please set with init() or initFromFile()\n");
		return;
	}
	if(verbose)printf("ofXML:  saving file %s \n", xmlFile.c_str());
	xMainNode.writeToFile(xmlFile.c_str());
}

//---------------------------------------------------------
void ofXML::clearTagContents(string tag)
{
	//This empties all elements inside a tag.
	//Can be used for clearing just the text
	//or for the child structures.
	XMLNode myNode = parseTag(tag);
	if(myNode.getName() != NULL)myNode.deleteNodeContent(1);
}

//---------------------------------------------------------
void ofXML::removeTag(string tag)
{
	//kind of ghetto way to remove a tag
	//we set its name to "" 
	//seems to work. This is in lui of 
	//not having a remove tag command
	XMLNode myNode = parseTag(tag);
	if(myNode.getName() != NULL){
		clearTagContents(tag);
		myNode.updateName("");
	}
}

//---------------------------------------------------------
int ofXML::getValue(string tag, int defaultValue)
{
	if( checkErrors() )return defaultValue;

	XMLNode myNode = parseTag(tag); 
	int val;

	//Added this to the XML Parser class
	//Returns true if the tag contains any text
	if( myNode.isText() ){
		//This only modifies the int if there is a value
		//So you can pass in a default value and it will
		//be not affected if no value can be found.
		val = atoi( myNode.getText() );
	}
	else{
		val = defaultValue;
		if(verbose)printf("ofXML:  tag %s not found value set to %i\n", tag.c_str(), defaultValue);
	}
	
	return val;
}

//---------------------------------------------------------
float ofXML::getValue(string tag, float defaultValue)
{
	if( checkErrors() )return defaultValue;

	XMLNode myNode = parseTag(tag); 
	float val;
	
	//Added this to the XML Parser class
	//Returns true if the tag contains any text
	if( myNode.isText() ){
		//This only modifies the float if there is a value
		//So you can pass in a default value and it will
		//be not affected if no value can be found.
		val = atof( myNode.getText() );
	}else{
		val = defaultValue;	
		if(verbose)printf("ofXML:  tag %s not found value set to %f\n", tag.c_str(),  defaultValue);
	}
	
	return val;	
}

//---------------------------------------------------------

string ofXML::getValue(string tag, string defaultValue)
{

	if( checkErrors() )return defaultValue;
	XMLNode myNode = parseTag(tag); 

	string val;

	//Added this to the XML Parser class
	//Returns true if the tag contains any text
	if( myNode.isText() ){
		//Warning you better pass in buffer large enough!!!
		//You need size of string you are getting +1
		//otherwise boom explosion!
		val = myNode.getText();
	}else{
		val = defaultValue;
		if(verbose)printf("ofXML:  tag %s not found value set to %s\n", tag.c_str(),  defaultValue.c_str());
	}
	
	return val;	
}



//---------------------------------------------------------

void ofXML::setValue(string tag, int value)
{
	string str = toString(value);
	setValue(tag, str);
}

//---------------------------------------------------------

void ofXML::setValue(string tag, float value)
{
	string str = toString(value);
	setValue(tag, str);
}


//---------------------------------------------------------

void ofXML::setValue(string tag, string value)
{
	
	//clean the tag of whitespace
	tag = cleanTag(tag);	
		
	//Now that a value has been set we def have something to read
	readingEnabled = true;

	if(!mainTagSet){
		if(verbose)printf("ofXML:  mainTag not set, please set with init() or initFromFile()\n");
		return;
	}

	XMLNode xNode;
	
	int index	= 0;
	int count	= 0;
	bool first	= true;
	int len 	= (int)tag.length();
	
	//Parse through the text one
	//char at a time
	while(index < len){
				
		//look for the seperator
		if(tag[count] == ':'){
			//create a tmp string to store the tag name
			string str;
			str.clear();
			
			//copy the tag to the string
			str = tag.substr(0,count);
			
			//and remove the tag and trailing :
			tag.erase(0, count+1); 	
			count = 0;
			
			//uncomment to debug errors
			//printf("TAG IS NOW %s \n", tag.c_str() );		
			//printf("STR IS NOW %s \n", str.c_str() );		
						
			//If this is the first tag
			//we need to reference the 
			//main node 
			if(first){
				xNode = xMainNode.getChildNode(str.c_str());	
				first = false;
				
				//If we are empty and have no text
				//then we don't exist.				
				if( xNode.getName() == NULL ){
					xMainNode.addChild(str.c_str());
				}
				
				xNode = xMainNode.getChildNode(str.c_str());	
			}
			else{
				
				//If we are empty and have no text
				//then we don't exist.
				//So let us create a new node
				//Might have to check for nodes with
				//no text.
				
				if( xNode.getChildNode(str.c_str()).getName() == NULL )	{
					xNode.addChild(str.c_str());
				}
		
				xNode = xNode.getChildNode(str.c_str());
			}
		}
		else{ 
			count++;
		}

		index++;
	}
	
	//Finally grab the last tag in the structure
	//which is the one we actually want to write
	//to
			
	//it could be the first tag ie "Red"
	//or it could be a child tag ie "Color:Red"
	//so we check
	
	string str = tag;
	
	if(first){
		xNode = xMainNode.getChildNode(str.c_str());
		if( xNode.getName() == NULL ){
			xMainNode.addChild(str.c_str());
		}
		xNode = xMainNode.getChildNode(str.c_str());
	}
	else{
		if( xNode.getChildNode(str.c_str()).getName() == NULL ){
			xNode.addChild(str.c_str());
		}
		xNode = xNode.getChildNode(str.c_str());
	}
	
    xNode.updateText(value.c_str());  
}

//---------------------------------------------------------

XMLNode ofXML::parseTag(string tag)
{

	//clean the tag of whitespace
	tag = cleanTag(tag);	
	
	//This is where we parse the tag.
	//We make sure that non-
	//existant tags don't crash the 
	//system. 
	
	//Tags can be in the format TAG
	//Representing <TAG>some text</TAG>
	
	//Or they can be in the format 
	//MainTag:InnerTag:Color:RED
	//Representing 
	/*
		<MainTag>
				<InnerTag>
					<Color>
						<RED>
							Some Value here
						</RED>
					</Color>
				</InnerTag>
		</MainTag>
	*/			
						
	XMLNode xNode;
	
	int index	= 0;
	int count 	= 0;
	bool first	= true;
	int len 	= (int)tag.length();

	//Parse through the text one
	//char at a time
	while(index < len){
		
		//look for the seperator
		if(tag[count] == ':'){
			//create a tmp string to store the tag name
			string str;
			str.clear();
			
			//copy the tag to the string
			str = tag.substr(0,count);
			
			//and remove the tag and trailing :
			tag.erase(0, count+1); 	
			count = 0;
			
			//uncomment to debug errors			
			//printf("TAG IS NOW %s \n", tag.c_str() );		
			//printf("STR IS NOW %s \n", str.c_str() );		
						
			//If this is the first tag
			//we need to reference the 
			//main node 
			if(first){
				xNode = xMainNode.getChildNode(str.c_str());
				first = false;
			}
			else{
				//Otherwise we get the child node
				xNode = xNode.getChildNode(str.c_str());
			}
						
			//If the tag is empty then 
			//we should stop
			if( xNode.isEmpty() ) break;
		}
		else{ 
			count++;
		}
		index++;
	}
	
	//Finally grab the last tag in the structure
	//which is the one we actually want to get the
	//contents of.
	
	//it could be the first tag ie "Red"
	//or it could be a child tag ie "Color:Red"
	//so we check
	if(first)xNode = xMainNode.getChildNode(tag.c_str());
	else xNode = xNode.getChildNode(tag.c_str());
	
	//finally we return the node
	//it might not contain anything or even exist
	//we do checking outside of this function
	//before using it
	return xNode;	
}

//---------------------------------------------------------

bool ofXML::checkErrors()
{
	if(!mainTagSet){
		if(verbose)printf("ofXML:  mainTag not set, please set with init() or initFromFile()\n");
		return true;
	}

	if(!readingEnabled){
		if(verbose)printf("ofXML:  nothing to read. either: no value set / file missing / file empty\n");
		return true;
	}
	
	return false;
}


//---------------------------------------------------------
//gets rid of all white space from the tag
//as this will cause a crash

string ofXML::cleanTag(string tag)
{
	int len 	= (int)tag.length();
	int index 	= 0;
	int count	= 0;
	
	string tmp(len, 0);
	
	while(index < len){
		if(tag[index] != ' '){
			tmp[count] = tag[index];
			count++;
		}
		index++;
	}
	
	tmp = tmp.substr(0,count);
		
	return tmp;
}

//---------------------------------------------------------

string ofXML::toString(float value){
	memset(toStrTmp, 0, 64);		
	sprintf(toStrTmp, "%f", value);
	
	string str = toStrTmp;	
	return str;
}

//--------------------------------------------------

string ofXML::toString(int value){
	memset(toStrTmp, 0, 64);		
	sprintf(toStrTmp, "%i", value);
	
	string str = toStrTmp;	
	return str;
}




