#include "ofXmlSettings.h"

#include <vector>
#include <string>
#include <iostream>

//----------------------------------------
// a pretty useful tokenization system:
static vector<string> tokenize(const string & str, const string & delim);
static vector<string> tokenize(const string & str, const string & delim)
{
  vector<string> tokens;

  size_t p0 = 0, p1 = string::npos;
  while(p0 != string::npos)
  {
    p1 = str.find_first_of(delim, p0);
    if(p1 != p0)
    {
      string token = str.substr(p0, p1 - p0);
      tokens.push_back(token);
    }
    p0 = str.find_first_not_of(delim, p1);
  }
  return tokens;
}
//----------------------------------------


ofXmlSettings::ofXmlSettings(){
	tagExists = false;
}

//---------------------------------------------------------
void ofXmlSettings::setVerbose(bool _verbose){
}

//---------------------------------------------------------
void ofXmlSettings::clear(){
	doc.Clear();
}

//---------------------------------------------------------
bool ofXmlSettings::loadFile(string xmlFile){
	bool loadOkay = doc.LoadFile(xmlFile.c_str());
	return loadOkay;
}

//---------------------------------------------------------
void ofXmlSettings::saveFile(string xmlFile){
	doc.SaveFile(xmlFile.c_str());

}

/*//---------------------------------------------------------
void ofXmlSettings::clearTagContents(string tag){
}

//---------------------------------------------------------
void ofXmlSettings::removeTag(string tag){
	
}*/

//---------------------------------------------------------
int ofXmlSettings::getValue(string tag, int defaultValue, int which){
	char * tempStr = new char[MAX_TAG_VALUE_LENGTH_IN_CHARS];
	memset(tempStr, 0, MAX_TAG_VALUE_LENGTH_IN_CHARS);
	int returnValue = defaultValue;

	if (readTag(tag, tempStr, which)){
		returnValue = atoi(tempStr);
	} 
	delete tempStr;
	return returnValue;
}

//---------------------------------------------------------
float ofXmlSettings::getValue(string tag, double defaultValue, int which){
	char * tempStr = new char[MAX_TAG_VALUE_LENGTH_IN_CHARS];
	memset(tempStr, 0, MAX_TAG_VALUE_LENGTH_IN_CHARS);
	float returnValue = defaultValue;

	if (readTag(tag, tempStr, which)){
		returnValue = atof(tempStr);
	} 
	delete tempStr;
	return returnValue;
}

//---------------------------------------------------------
string ofXmlSettings::getValue(string tag, string defaultValue, int which){
	
	// lots of char *, string kung-fu here...
	
	char * tempStr = new char[MAX_TAG_VALUE_LENGTH_IN_CHARS];
	memset(tempStr, 0, MAX_TAG_VALUE_LENGTH_IN_CHARS);
	char * returnPtr = (char *) defaultValue.c_str();
	if (readTag(tag, tempStr, which)){
		returnPtr = tempStr;
	} 
	string returnString(returnPtr);
	delete tempStr;
	return returnString;
}

//---------------------------------------------------------
bool ofXmlSettings::getSuccess(){
	return tagExists;
}


//---------------------------------------------------------
bool ofXmlSettings::readTag(string  tag, char * valueString, int which){

	vector<string> tokens = tokenize(tag,":");
		
	
	TiXmlHandle docHandle(&doc);
	TiXmlHandle tagHandle = docHandle;
	for(int x=0;x<tokens.size();x++){
		if(x == 0)tagHandle = tagHandle.ChildElement(tokens.at(x), which);
		else tagHandle = tagHandle.FirstChildElement( tokens.at(x) );
	}

	// once we've walked, let's get that value...
	TiXmlHandle valHandle = tagHandle.Child( 0 );
    
    //now, clear that vector! 
	tokens.clear();		
	
    // if that value is really text, let's get the value out of it ! 
    if (valHandle.Text()){
    	int maxLen = MIN(MAX_TAG_VALUE_LENGTH_IN_CHARS, strlen(valHandle.Text()->Value()));
    	memcpy(valueString, valHandle.Text()->Value(), maxLen);
		tagExists = true;
    	return true;	
    }  else {
		tagExists = false;
		return false;
	}
}

//---------------------------------------------------------
void ofXmlSettings::addTag(string  tag, char * valueStr){
	
	vector<string> tokens = tokenize(tag,":");
	
	// allocate then clean up :
	
	TiXmlElement ** elements = new TiXmlElement*[tokens.size()];
	for(int x=0;x<tokens.size();x++){
		elements[x] = new TiXmlElement(tokens.at(x));
	}
	
	TiXmlText Value(valueStr);			
	
	// search our way up - do these tags exist?
	// find the first that DOESNT exist, then move backwards...
	TiXmlHandle docHandle(&doc);
	TiXmlHandle tagHandle = docHandle;
	
	for(int x=0;x<tokens.size();x++){
		
		TiXmlHandle isRealHandle  = tagHandle.FirstChildElement( tokens.at(x) );
		
		if (!isRealHandle.Node()){
			
			for(int i=tokens.size()-1;i>=x;i--){
				if (i == tokens.size()-1){
					elements[i]->InsertEndChild(Value);
				} else {
					elements[i]->InsertEndChild(*(elements[i+1]));
				}
			}
			
			
			
			tagHandle.ToNode()->InsertEndChild(*(elements[x]));
			
			break;
			
		} else {
			 tagHandle = isRealHandle;
			 if (x == tokens.size()-1){
				// what we want to change : TiXmlHandle valHandle = tagHandle.Child( 0 );
				tagHandle.ToNode()->Clear();
				tagHandle.ToNode()->InsertEndChild(Value);
			}
		}
	}
	
	//now, clear that vector! 
	tokens.clear();		
}

//---------------------------------------------------------
void ofXmlSettings::setValue(string tag, int	value){
	char valueStr[255];
	sprintf(valueStr, "%i", value);
	addTag(tag, valueStr);
}

//---------------------------------------------------------
void ofXmlSettings::setValue(string  tag, double 	value){
	char valueStr[255];
	sprintf(valueStr, "%f", value);
	addTag(tag, valueStr);
}

//---------------------------------------------------------
void ofXmlSettings::setValue(string tag, string value){
	addTag(tag, (char *)value.c_str());
	
}
