#ifndef __XML_HEADER__
#define __XML_HEADER__

#if _MSC_VER > 1000
#pragma once
#endif

#include <string>
using std::string;

#include <vector>
#include <set>

#pragma warning(3: 4263)
#pragma warning(3: 4264)

typedef char const* cstr;

// Wrapper for string that does automatic conversion to cstr.
class XmlString : public string
{
public:
	XmlString() {};
	XmlString( cstr str ) : string(str) {};
	XmlString( string const& str ) : string(str) {};
#ifdef  _AFX
	XmlString( const CString &str ) : string( (cstr)str ) {};
#endif // _AFX

	operator cstr() const { return c_str(); }
};

/**
******************************************************************************
* XmlAttribute class
******************************************************************************
*/

//////////////////////////////////////////////////////////////////////////
class XmlAttribute 
{
public:
	XmlString key, value;

	bool operator<( const XmlAttribute &attr ) const { return key < attr.key; }
	bool operator>( const XmlAttribute &attr ) const { return key > attr.key; }
	bool operator==( const XmlAttribute &attr ) const { return key == attr.key; }
	bool operator!=( const XmlAttribute &attr ) const { return key != attr.key; }
};


//! Xml node attributes class.
typedef std::vector<XmlAttribute>	XmlAttributes;

class XmlNode
{
public:
	//! Constructor.
	XmlNode( cstr tag );
	//! Destructor.
	~XmlNode();

	//////////////////////////////////////////////////////////////////////////
	//! Reference counting.
	void AddRef() { m_refCount++; };
	//! When ref count reach zero XML node dies.
	void Release() { if (--m_refCount <= 0) delete this; };

	//! Get XML node tag.
	XmlString const& getTag() const { return m_tag; };
	void	setTag( cstr tag ) { m_tag = tag; }

	//! Return true if givven tag equal to node tag.
	bool isTag( cstr tag ) const;

	//! Get XML Node attributes.
	int getNumAttributes() const { return (int)m_attributes.size(); };
	//! Return attribute key and value by attribute index.
	bool getAttributeByIndex( int index, XmlString *key, XmlString *value );

	void copyAttributes( XmlNode const& fromNode );

	//! Get XML Node attribute for specified key.
	XmlString const& getAttr( cstr key ) const;
	//! Check if attributes with specified key exist.
	bool haveAttr( cstr key ) const;
	
	//! Adds new child node.
	void addChild( XmlNode* node, int pos = -1 );

	//! Creates new xml node and add it to childs list.
	XmlNode* newChild( cstr tagName );

	//! Remove child node.
	void removeChild( XmlNode* node );

	//! Remove all child nodes.
	void removeAllChilds();

	//! Get number of child XML nodes.
	int	getChildCount() const { return (int)m_childs.size(); };
	
	//! Get XML Node child nodes.
	XmlNode* getChild( int i ) const;

	//! Find node with specified tag.
	XmlNode* findChild( cstr tag ) const;
	XmlNode* findChild( XmlString const& tag, XmlString const& attr, XmlString const& name );
	void deleteChild( cstr tag );
	void deleteChildAt( int nIndex );

	//! Get parent XML node.
	XmlNode*	getParent() const { return m_parent; }

	//! Returns content of this node.
	XmlString const& getContent() const { return m_content; };
	void setContent( cstr str ) { m_content = str; };
	void addContent( cstr str ) { m_content += str; };

	XmlNode*	clone();

	//! Returns line number for XML tag.
	int getLine() const { return m_line; };
	//! Set line number in xml.
	void setLine( int line ) { m_line = line; };

	//! Returns XML of this node and sub nodes.
	XmlString getXML( int level=0 );
	bool saveToFile( cstr fileName );

	//! Set new XML Node attribute (or override attribute with same key).
	void setAttr( cstr key, cstr value );
	void setAttr( cstr key, int value );
	void setAttr( cstr key, unsigned int value );
	void setAttr( cstr key, float value );

	//! Delete attrbute.
	void delAttr( cstr key );
	//! Remove all node attributes.
	void removeAllAttributes();

	//! Get attribute value of node.
	bool getAttr( cstr key, XmlString &value ) const;
	bool getAttr( cstr key, int &value ) const;
	bool getAttr( cstr key, unsigned int &value ) const;
	bool getAttr( cstr key, float &value ) const;
	bool getAttr( cstr key, bool &value ) const;

private:
	//! Ref count itself, its zeroed on node creation.
	int m_refCount;

	//! Line in XML file where this node firstly appeared (usefull for debuggin).
	int m_line;
	//! Tag of XML node.
	XmlString m_tag;

	//! Content of XML node.
	XmlString m_content;
	//! Parent XML node.
	XmlNode *m_parent;
	//! Next XML node in same hierarchy level.
	
	typedef std::vector<XmlNode*>	XmlNodes;
	XmlNodes m_childs;
	//! Xml node attributes.
	XmlAttributes m_attributes;
	static XmlAttribute tempAttr;
};

/************************************************************************/
/* XmlParser class, Parse xml and return root xml node if success.      */
/************************************************************************/
class XmlParser
{
public:
	//! Parse xml file.
	XmlNode* parse( cstr fileName );

	//! Parse xml from memory buffer.
	XmlNode* parseBuffer( cstr buffer );

	string const& getErrorString() const { return m_errorString; }
private:
	XmlString m_errorString;
};


#endif // __XML_HEADER__