#include <ZUtil/ZXMLWriter.hpp>

#define APPEND_NEWLINE \
		if (_useNewlines) { \
			ZStringAlgo::Append(_output, LINE_TERMINATOR); \
		} \

const ZString& ZXMLWriter::GetErrorString()
{
	return ErrorMessage;
}

bool ZXMLWriter::writeAttributes(ZString& _output, const ZKVTree::Iterator& _itr) 
{
	bool found_sub = false;						// indicates we have sub-elements

	for (size_t i = 0; i < _itr.GetChildCount(); i++) {

		const ZKVTree::Iterator itr = _itr.ChildItr(i);

		if (itr.GetChildCount() > 0) {			// attributes have no children
			found_sub = true;
			continue;
		}

		const ZString& name = itr.GetName();	// attrib name
		const ZString& val  = itr.GetValue();	// attrib value

		_output.PushBack(' ');					// start with a space
		ZStringAlgo::Append(_output, name);		// append attribute name
		_output.PushBack('=');					// equals
		_output.PushBack('\"');					// escaped quote
		ZStringAlgo::Append(_output, val);		// attribute value
		_output.PushBack('\"');					// escaped quote
	}

	return found_sub;
}

bool ZXMLWriter::writeElements(ZString& _output, bool _useNewlines, const ZKVTree::Iterator& _itr)
{
	if (_itr.GetChildCount() == 0) {					// indicates an attribute
		return true;
	}

	const ZString& name = _itr.GetName();				// element name
	const ZString& val  = _itr.GetValue();				// element value

	_output.PushBack('<');								// open tag
	ZStringAlgo::Append(_output, name);					// element name

	bool found_sub = writeAttributes(_output, _itr);	// write all attributes

	if (val.Empty() && !found_sub) {					// close the tag, no body, no sub-elements
		_output.PushBack('/');
		_output.PushBack('>');

		APPEND_NEWLINE;

	} else {											// keep tag open for sub-elements and body
		_output.PushBack('>');

		APPEND_NEWLINE;

		// write all sub-elements (this does nothing on an attribute)
		for (size_t i = 0; i < _itr.GetChildCount(); i++) {		
			writeElements(_output, _useNewlines, _itr.ChildItr(i));
		}

		if (!val.Empty()) {
			ZStringAlgo::Append(_output, val);			// write element body
			APPEND_NEWLINE;
		}

		_output.PushBack('<');							// closing tag begin
		_output.PushBack('/');
		ZStringAlgo::Append(_output, name);
		_output.PushBack('>');							// closing tag end

		APPEND_NEWLINE;
	}
	
	return true;
}

bool ZXMLWriter::Write( const ZKVTree& _input, ZString& _output, bool _useNewlines )
{	
	ZKVTree::Iterator itr = _input.Begin();

	if (itr == _input.End()) {
		ErrorMessage = "ZXMLWriter: key value tree has no data!";
		return false;
	}
	
	return writeElements(_output, _useNewlines, itr);
}
