//****************************************************************************
// Filename: XmlElements.h
// Copyright 1999 Daniel X. Pape. All rights reserved.
//
// Description: A set of classes for reading and parsing simple XML files.
//
//****************************************************************************
// Revision History:
// Thursday, July 08, 1999 - Original. Heavily based on "A Simple XML
//   Parser" by Sebastien Andrivet. See Documentation.
//****************************************************************************

#ifndef _XMLELEMENTS_H_
#define _XMLELEMENTS_H_

#ifdef _MSC_VER
// Disable stupid MSVC warning about identifiers > 255 chars long
#pragma warning (disable: 4786)
#endif

// STL
#include <memory>

#include "XmlFwdDecls.h"

namespace SimpleXMLParser
{

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

class Attribute;
class Element;
class ElementNull;

typedef std::map<std::string, std::string>  Attributes;
typedef std::vector<Element*>    Elements;

// ***************************************************************************
//    Class: Attribute
//     Desc: 
// ***************************************************************************
class Attribute
{
    std::string  name_;
    std::string  value_;

public:

    Attribute(const std::string& name, const std::string& value);

    const std::string& GetName() const;
    const std::string& GetValue() const;
};

// ***************************************************************************
//    Class: Value
//     Desc: 
// ***************************************************************************
class Value
{
    std::string  value_;

public:

    void Add(const std::string& text);
    void Add(char c);

    // Conversion operator
    operator const std::string&() const;
};

// ***************************************************************************
//    Class: Element
//     Desc: Abstract base class for markup tags
// ***************************************************************************
class Element
{
private:
    const std::string    name_;
    Value           value_;

public:

    static ElementNull& nullElem;   // null element (singleton)

    Element(const std::string& strName);
    virtual ~Element() { }

    void AddValue(const std::string& strText);
    void AddValue(char c);

    const std::string& GetName() const;
    const Value& GetValue() const;

    const Element& operator()(const char * szName, int nIndex = 0) const;

	virtual bool IsNull() const;

    virtual bool AddChild(Element* pChild) = 0;

    virtual const Elements* GetChildren() const = 0;
	virtual const Element& GetChild(const char * szName, 
                                    int nIndex = 0) const = 0;

	virtual const Attributes* GetAttributes() const = 0;
	virtual const std::string GetAttributeValue(const std::string&) const = 0;
};

// ***************************************************************************
//    Class: ElementTag
//     Desc: Element of the form <name>...</name> or <name/>. Can
//     contain other elements and may have attributes
// ***************************************************************************
class ElementTag : public Element
{

public:

    ElementTag(const std::string& strName);
    ~ElementTag();

    void AddAttribute(std::string& strName, std::string& strValue);

    virtual bool AddChild(Element* pChild);

    virtual const Elements* GetChildren() const;
	virtual const Element& GetChild(const char * szName, int nIndex = 0) const;

	virtual const Attributes* GetAttributes() const;
	virtual const std::string GetAttributeValue(const std::string&) const;

private:

    bool FindChild(const char * szName, Elements::const_iterator& it) const;

    Attributes  attributes_;
    Elements    children_;

};

// ***************************************************************************
//    Class: ElementSimple
//     Desc: Element without children (like comments)
// ***************************************************************************
class ElementSimple: public Element
{
public:
    ElementSimple(const std::string& strName);

    virtual bool AddChild(Element* pChild);

    virtual const Elements* GetChildren() const;
	virtual const Element& GetChild(const char * szName, int nIndex = 0) const;

	virtual const Attributes* GetAttributes() const;
    virtual const std::string GetAttributeValue(const std::string&) const;
};

// ***************************************************************************
//    Class: ElementComment
//     Desc: Element named "!"
// ***************************************************************************
class ElementComment : public ElementSimple
{
public:
    ElementComment(const std::string& strComment);
};

// ***************************************************************************
//    Class: ElementNull
//     Desc: Element::nullElem
// ***************************************************************************
class ElementNull : public ElementSimple
{
public:
    ElementNull();

private:
	virtual bool IsNull() const;
};

//////////////////////////////////////////////////////////////////////
// Attribute of a tag
//////////////////////////////////////////////////////////////////////

inline const std::string& Attribute::GetName() const
{
    return(name_);
}

inline const std::string& Attribute::GetValue() const
{
    return(value_);
}

//////////////////////////////////////////////////////////////////////
// Element
//////////////////////////////////////////////////////////////////////

inline const std::string& Element::GetName() const
{
    return(name_);
}

inline const Value& Element::GetValue() const
{
    return(value_);
}

inline void Element::AddValue(const std::string& strText)
{
    value_.Add(strText);
}

inline void Element::AddValue(char c)
{
    value_.Add(c);
}

inline const Element& 
Element::operator()(const char * szName, int nIndex) const
{
    return(GetChild(szName, nIndex));
}

inline void 
ElementTag::AddAttribute(std::string& strName, std::string& strValue)
{
    attributes_[strName] = strValue;
}

}

#endif

