////////////////////////////////////////////////////////////////////////////////
// XMLTree.h
// Copyright Bjoern Ganster 
// Developed since 2005
////////////////////////////////////////////////////////////////////////////////

#ifndef XMLTree__H
#define XMLTree__H

#include "BGCPString.h"

#include <vector>

////////////////////////////////////////////////////////////////////////////////
// Records used by XMLTree

struct XMLAttribute: public VirtualClass
{
	BGCPString m_name, m_value;
	XMLAttribute(const BGCPString& _name, const BGCPString& _value);
};

class XMLTreeNode: public VirtualClass
{
public:
	// Constructor
	XMLTreeNode(XMLTreeNode* parent, const BGCPString& name, const BGCPString& text = BGCPString());

	// Destructor
	~XMLTreeNode() OVERRIDE;

	// Deep copies are not supported here
	DELETE_FUNC(XMLTreeNode(const XMLTreeNode& other));
	DELETE_FUNC(void operator=(const XMLTreeNode& other));

	// Get parent
	XMLTreeNode* getParent();
	const XMLTreeNode* getParent() const;

	XMLAttribute* addAttribute(const BGCPString& attr, const BGCPString& value);

	size_t getAttributeCount() const;

	bool getAttributeName(size_t i, BGCPString& name) const;

	bool getAttributeValueByIndex(size_t i, BGCPString& value) const;

	bool isRoot() const NOEXCEPT;

	void setName(const BGCPString& newName);
	const BGCPString& getName() const NOEXCEPT;

	// Access childs
	size_t getChildCount() const NOEXCEPT;
	XMLTreeNode* getChild(size_t i) NOEXCEPT;
	const XMLTreeNode* getChild(size_t i) const NOEXCEPT;
	void addChild(XMLTreeNode* newChild);

	const BGCPString& getText() const NOEXCEPT;
	void setText(const BGCPString& text);

private:
	BGCPString m_name, m_text;
	XMLTreeNode* m_parent;
	std::vector <XMLTreeNode*> m_childs;
	std::vector <XMLAttribute*> m_attributes;
};

////////////////////////////////////////////////////////////////////////////////
// Class XMLTree

class XMLTreeConstIterator: public VirtualClass
{
public:
	// Constructors
	XMLTreeConstIterator(const XMLTreeNode* node = NULL);

	// Copy constructor
	XMLTreeConstIterator(const XMLTreeConstIterator& iter);

	// Destructor
	~XMLTreeConstIterator();

	// XML tree navigation
	bool goToParent() NOEXCEPT;
	bool goToChild(size_t child);
	bool goToChildByName(const BGCPString& childName);
	void goToRoot() NOEXCEPT;

	// Getters
	bool getNodeName(BGCPString& name) const;
	bool getAttributeName(size_t i, BGCPString& str) const;
	bool getAttributeValueByIndex(size_t i, BGCPString& value) const;
	int64_t getIntAttributeValueByName(const BGCPString& aAttrName, int64_t defaultVal = 0) const;
	bool hasAttribute(const BGCPString& searchedAttrName) const;
	double getDoubleAttributeByName(const BGCPString& attrName, double defaultVal = 0.0) const;

	// Scan the attributes of the current node for the given attrName and puts its value into value
	// If nothing is found, value is left unchanged.
	bool getAttributeValueByName(const BGCPString& attrName, BGCPString& value) const;

	BGCPString getText() const;
	size_t getChildCount() const NOEXCEPT;
	size_t getAttributeCount() const NOEXCEPT;

	bool isRoot() const NOEXCEPT;

	const XMLTreeNode* getTreeNode() const NOEXCEPT;

	// Check if a node name equals the given string (case-insensitive)
	bool nodeNameEquals(const BGCPString& str) const;

protected:
	const XMLTreeNode* m_currNode;
};

class XMLTree;

class XMLTreeIterator: public VirtualClass
{
public:
	// Constructors
	XMLTreeIterator(XMLTree* tree, XMLTreeNode* node = NULL);
	XMLTreeIterator(const XMLTreeIterator& iter);

	// XML tree navigation
	bool goToParent() NOEXCEPT;
	bool goToChild(size_t child);
	bool goToChildByName(const char* childName);
	void goToRoot() NOEXCEPT;

	// Getters
	bool getNodeName(BGCPString& name) const;

	BGCPString getAttributeName(size_t i) const;

	bool getAttributeValueByIndex(size_t i, BGCPString& val) const;

	bool getAttributeValueByName(const BGCPString& aAttrName, BGCPString& val) const;

	BGCPString getText() const;
	size_t getChildCount() const;
	size_t getAttributeCount() const;

	bool isRoot() const;

	const XMLTreeNode* getTreeNode() const;

	// Add a child to a node, returning its number
	size_t addChild(const BGCPString& name);

	// Add an attribute 
	bool addAttribute(const BGCPString& name, const BGCPString& value);

	void addAttribute(const BGCPString& name, int value);

	void addIntAttribute(const BGCPString& attr, int64_t value);

	void addDoubleAttribute(const BGCPString& attr, double value, int precision = 3);

	// Add text to a node
	bool addText(const BGCPString& text);

	// Create a copy of a part of another tree
	void copyFromChilds(XMLTreeConstIterator& constIter);

protected:
	XMLTreeNode* m_currNode;
	XMLTree* m_tree;
};

///////////////////////////////////////////////////////////////////////////////

class XMLTree : public VirtualClass
{
public:
	BGCPString indentStr;

	// Construct
	XMLTree();

	// Construct with named root node
	XMLTree(const BGCPString& rootNodeName);

	// Destructor
	~XMLTree() OVERRIDE;

	// Load XML from file
	bool loadFromFile(const PathChar* path);

	// Parse XML from string
	bool parse(const BGCPString& data);

	// Save XML to string
	bool saveToString(BGCPString& out);

	// Save XML to file
	bool saveToFile(const PathChar* fn, WORD cp);

	// Iterators construction - removed
	// These functions constructed objects on the heap. Better construct the iterators on the heap by passing an XMLTreeNode* to 
	// the appropriate constructor. 
	//XMLTreeIterator* getIterator();
	//XMLTreeConstIterator* getConstIterator();

	// Root access
	void setRoot(XMLTreeNode* newRoot);
	XMLTreeNode* getRoot();
	const XMLTreeNode* getRoot() const;

private:
	XMLTreeNode* root;
	bool recSave(BGCPString& out, unsigned int indents, XMLTreeNode* node);
};

// Copy XML tree nodes
void copyNodesRecursively(XMLTreeConstIterator* inIter, XMLTreeIterator* outIter);

#endif
