/** 
 * @file llxmltree.h
 * @author Aaron Yonas, Richard Nelson
 * @brief LLXmlTree class definition
 *
 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#ifndef LL_LLXMLTREE_H
#define LL_LLXMLTREE_H

#include <map>
#include <list>
#include "llstring.h"
#include "llxmlparser.h"
#include "llstringtable.h"

class LLColor4;
class LLColor4U;
class LLQuaternion;
class LLUUID;
class LLVector3;
class LLVector3d;
class LLXmlTreeNode;
class LLXmlTreeParser;

//////////////////////////////////////////////////////////////
// LLXmlTree

class LLXmlTree
{
	friend class LLXmlTreeNode;
	
public:
	LLXmlTree();
	virtual ~LLXmlTree();
	void cleanup();

	virtual BOOL	parseFile(const std::string &path, BOOL keep_contents = TRUE);
	virtual BOOL	parseString(const std::string &string, BOOL keep_contents = TRUE);

	LLXmlTreeNode*	getRoot() { return mRoot; }

	void			dump();
	void			dumpNode( LLXmlTreeNode* node, const std::string& prefix );

	static LLStdStringHandle addAttributeString( const std::string& name)
	{
		return sAttributeKeys.addString( name );
	}
	
public:
	// global
	static LLStdStringTable sAttributeKeys;
	
protected:
	LLXmlTreeNode* mRoot;

	// local
	LLStdStringTable mNodeNames;	
};

//////////////////////////////////////////////////////////////
// LLXmlTreeNode

class LLXmlTreeNode
{
	friend class LLXmlTree;
	friend class LLXmlTreeParser;

protected:
	// Protected since nodes are only created and destroyed by friend classes and other LLXmlTreeNodes
	LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LLXmlTree* tree );
	
public:
	virtual ~LLXmlTreeNode();

	const std::string&	getName()
	{
		return mName;
	}
	BOOL hasName( const std::string& name )
	{
		return mName == name;
	}

	BOOL hasAttribute( const std::string& name );

	// Fast versions use cannonical_name handlee to entru in LLXmlTree::sAttributeKeys string table
	BOOL			getFastAttributeBOOL(		LLStdStringHandle cannonical_name, BOOL& value );
	BOOL			getFastAttributeU8(			LLStdStringHandle cannonical_name, U8& value );
	BOOL			getFastAttributeS8(			LLStdStringHandle cannonical_name, S8& value );
	BOOL			getFastAttributeU16(		LLStdStringHandle cannonical_name, U16& value );
	BOOL			getFastAttributeS16(		LLStdStringHandle cannonical_name, S16& value );
	BOOL			getFastAttributeU32(		LLStdStringHandle cannonical_name, U32& value );
	BOOL			getFastAttributeS32(		LLStdStringHandle cannonical_name, S32& value );
	BOOL			getFastAttributeF32(		LLStdStringHandle cannonical_name, F32& value );
	BOOL			getFastAttributeF64(		LLStdStringHandle cannonical_name, F64& value );
	BOOL			getFastAttributeColor(		LLStdStringHandle cannonical_name, LLColor4& value );
	BOOL			getFastAttributeColor4(		LLStdStringHandle cannonical_name, LLColor4& value );
	BOOL			getFastAttributeColor4U(	LLStdStringHandle cannonical_name, LLColor4U& value );
	BOOL			getFastAttributeVector3(	LLStdStringHandle cannonical_name, LLVector3& value );
	BOOL			getFastAttributeVector3d(	LLStdStringHandle cannonical_name, LLVector3d& value );
	BOOL			getFastAttributeQuat(		LLStdStringHandle cannonical_name, LLQuaternion& value );
	BOOL			getFastAttributeUUID(		LLStdStringHandle cannonical_name, LLUUID& value );
	BOOL			getFastAttributeString(		LLStdStringHandle cannonical_name, std::string& value );

	// Normal versions find 'name' in LLXmlTree::sAttributeKeys then call fast versions
	virtual BOOL		getAttributeBOOL(		const std::string& name, BOOL& value );
	virtual BOOL		getAttributeU8(			const std::string& name, U8& value );
	virtual BOOL		getAttributeS8(			const std::string& name, S8& value );
	virtual BOOL		getAttributeU16(		const std::string& name, U16& value );
	virtual BOOL		getAttributeS16(		const std::string& name, S16& value );
	virtual BOOL		getAttributeU32(		const std::string& name, U32& value );
	virtual BOOL		getAttributeS32(		const std::string& name, S32& value );
	virtual BOOL		getAttributeF32(		const std::string& name, F32& value );
	virtual BOOL		getAttributeF64(		const std::string& name, F64& value );
	virtual BOOL		getAttributeColor(		const std::string& name, LLColor4& value );
	virtual BOOL		getAttributeColor4(		const std::string& name, LLColor4& value );
	virtual BOOL		getAttributeColor4U(	const std::string& name, LLColor4U& value );
	virtual BOOL		getAttributeVector3(	const std::string& name, LLVector3& value );
	virtual BOOL		getAttributeVector3d(	const std::string& name, LLVector3d& value );
	virtual BOOL		getAttributeQuat(		const std::string& name, LLQuaternion& value );
	virtual BOOL		getAttributeUUID(		const std::string& name, LLUUID& value );
	virtual BOOL		getAttributeString(		const std::string& name, std::string& value );

	const std::string& getContents()
	{
		return mContents;
	}
	std::string getTextContents();

	LLXmlTreeNode*	getParent()							{ return mParent; }
	LLXmlTreeNode*	getFirstChild();
	LLXmlTreeNode*	getNextChild();
	S32				getChildCount()						{ return (S32)mChildren.size(); }
	LLXmlTreeNode*  getChildByName( const std::string& name );	// returns first child with name, NULL if none
	LLXmlTreeNode*  getNextNamedChild();				// returns next child with name, NULL if none

protected:
	const std::string* getAttribute( LLStdStringHandle name)
	{
		attribute_map_t::iterator iter = mAttributes.find(name);
		return (iter == mAttributes.end()) ? 0 : iter->second;
	}

private:
	void			addAttribute( const std::string& name, const std::string& value );
	void			appendContents( const std::string& str );
	void			addChild( LLXmlTreeNode* child );

	void			dump( const std::string& prefix );

protected:
	typedef std::map<LLStdStringHandle, const std::string*> attribute_map_t;
	attribute_map_t						mAttributes;

private:
	std::string							mName;
	std::string							mContents;
	
	typedef std::vector<class LLXmlTreeNode *> children_t;
	children_t                          mChildren;
	children_t::iterator				mChildrenIter;
	
	typedef std::multimap<LLStdStringHandle, LLXmlTreeNode *> child_map_t;
	child_map_t							mChildMap;		// for fast name lookups
	child_map_t::iterator				mChildMapIter;
	child_map_t::iterator				mChildMapEndIter;

	LLXmlTreeNode*						mParent;
	LLXmlTree*							mTree;
};

//////////////////////////////////////////////////////////////
// LLXmlTreeParser

class LLXmlTreeParser : public LLXmlParser
{
public:
	LLXmlTreeParser(LLXmlTree* tree);
	virtual ~LLXmlTreeParser();

	BOOL parseFile(const std::string &path, LLXmlTreeNode** root, BOOL keep_contents );
	BOOL parseString(const std::string &string, LLXmlTreeNode** root, BOOL keep_contents);

protected:
	const std::string& tabs();

	// Overrides from LLXmlParser
	virtual void	startElement(const char *name, const char **attributes); 
	virtual void	endElement(const char *name);
	virtual void	characterData(const char *s, int len);
	virtual void	processingInstruction(const char *target, const char *data);
	virtual void	comment(const char *data);
	virtual void	startCdataSection();
	virtual void	endCdataSection();
	virtual void	defaultData(const char *s, int len);
	virtual void	unparsedEntityDecl(
		const char* entity_name,
		const char* base,
		const char* system_id,
		const char* public_id,
		const char* notation_name);

	//template method pattern
	virtual LLXmlTreeNode* CreateXmlTreeNode(const std::string& name, LLXmlTreeNode* parent);

protected:
	LLXmlTree*		mTree;
	LLXmlTreeNode*	mRoot;
	LLXmlTreeNode*  mCurrent;
	BOOL			mDump;	// Dump parse tree to LL_INFOS() as it is read.
	BOOL			mKeepContents;
};

#endif  // LL_LLXMLTREE_H
