root/src/Tag.h

////////////////////////////////////////////////////////////////////////
// Copyright (c) Nehmulos 2011-2014
// This file is part of N0 Strain Serialization Library.
//
// N0Strain-Serialization-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, either version 3 of the License, or
// (at your option) any later version.
//
// N0Strain-Serialization-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 N0Strain-Serialization-Library.  If not, see https://gnu.org/licenses/lgpl-3.0
////////////////////////////////////////////////////////////////////////




#ifndef TAG_H_
#define TAG_H_

#include <string>
#include <sstream>
#include <vector>
#include <stack>
#include <fstream>
#include <iostream>

#include "N0SlibConstants.h"
#include "N0SlibUtils.h"


namespace nw {

/// workaround for template type-Overloading
/// many thanks to Johannes Schaub
/// http://stackoverflow.com/questions/3052579/explicit-specialization-in-non-namespace-scope/3057522#3057522
template<typename T> struct identity { typedef T type; };

/// States for the XmlParser. TODO 1.2 move to XmlReader
typedef enum
{
        readTagType,
        readTagName,
        searchNewTags,
        closeTag,

        searchAttributes,
        readAttributeName,
        assignAttribute,
        readAttributeValue,

        readXmlVersion,
        readCommentType,
        definitionTagName,
        definitionValue,
        cDataTagName,
        cDataValue,
        xmlComment,
} PARSER_STATE;
class Tag {
public:
        Tag();                                  ///< Set's the name to "Unnamed"
        Tag(const String tagName);      ///< Set's the Tag's name
        virtual ~Tag();

        virtual Tag* addNewChild(const String tagName); ///< Adds a new Tag with the given Name and without value.

        template <class T>
        Tag* addNewChild(const String tagName, const String tagValue) ///< Adds a new Tag with the given String value.
        {
                Tag* newChild = new Tag(tagName);
                newChild->setValue(tagValue);
                newChild->setParent(this);
                newChild->setLevel(this->level+1);
                children.push_back(newChild);
                return newChild;
        }

        template <class T>
        Tag* addNewChild(const String tagName, T tagValue) ///< Adds a new Tag with the given String value.
        {
                Tag* newChild = new Tag(tagName);
                newChild->setValue(tagValue);
                newChild->setParent(this);
                newChild->setLevel(this->level+1);
                children.push_back(newChild);
                return newChild;
        }

        void addComment(const String text);                             ///< Adds a new Tag as a comment
        void addChild(Tag* child);                                      ///< Add's a childTag to the childrenVector.
        void removeChild(Tag* child);                           ///< Removes a childTag form the vector. Does not Delete.

        bool hasGrandChildren(); ///< scary helper I provided publicly for some reason
        bool hasChildren();              ///< Returns true if the childrenVector is not empty

        /// Get the first child-Tag for the given Name.
        /// Returns NULL if there is no childtag with such a name.
        Tag* getChildWithName(const String childrenTagName);
        Tag* getLastChild();                                            ///< Get the latest added child
        String getName();                                                       ///< Get the tag's name
        String getValue();                                                      ///< Get the value String

        long double getLongDoubleValue();                       ///< Converts the value String
        long long   getLongLongValue();                         ///< Converts the value String

        double getDoubleValue();                                        ///< Converts the value String
        float  getFloatValue();                                         ///< Converts the value String
        long   getLongValue();                                          ///< Converts the value String
        int    getIntegerValue();                                       ///< Converts the value String
        short  getShortValue();                                         ///< Converts the value String
        bool   getBooleanValue();                                       ///< Parse "true" and "1" as true, everything else as false
        void*  getPointerValue();                                       ///< Converts the value String
        char   getCharacterValue();                                     ///< Converts the value String

        template<typename T> T getValueAs()
        {
                return getValueAs(identity<T>());
        }

        unsigned char  getUnsignedCharacterValue();     ///< Converts the value String
        signed   char  getSignedCharacterValue();       ///< Converts the value String
        unsigned short getUnsignedShortValue();         ///< Converts the value String
        unsigned int   getUnsignedIntegerValue();       ///< Converts the value String
        unsigned long  getUnsignedLongValue();          ///< Converts the value String

        void*  getBase64Value();                                        ///< Converts the value String and creates a pointer to the result
        void*  getHexValue();                       ///< Converts the value String and creates a pointer to the result
        std::stack<Tag*> getCsvTags();                   ///< Parse a CsvString into a stack of Tags (specialized for MarkupReder)
        Tag* getParent();                                                       ///< Returns the Parent Tag.
        std::vector<Tag*>& getChildren();                               ///< Returns a reference to a vector of it's child tags

        void setParent(Tag* parent);                            ///< Set's a new Parent Tag.
        void setName(const String value);                                       ///< Set's the Tag's name
        void setValue(const String value);                              ///< Set's the Tag's value String
        template <class T>
        void setValue(T value)                          ///< Set's the Tag's value String
        {
                std::stringstream ss;
                String stringValue;
                ss << value;
                ss >> stringValue;
                setValue(stringValue);
        }
        static void writeXmlHeader(std::ostream& file);   ///< Writes the Header for a xml File, TODO 1.2 move to xmlWriter
//      static String valueToHexaDecimalString(String value);
        void writeAsXmlWithAttributes(std::ostream& file); ///< Writes the current Tag and it's children to a fstream

        static bool useAttribute;                       ///< Init value for canBeAttribute

        void setLevel(int level);                       ///< Sets the numberOfTabs used
        bool operator==(Tag& that);                     ///< Returns true if the values and names are equal
    bool getIsComent() const;                   ///< Returns true if the tag is a comment
    bool getCanBeAttribute() const;             ///< Returns ture if canBeAttribute is true
    void setIsComment(bool isComment);  ///< Sets if the Tag is written as Comment
    void setCanBeAttribute(bool canBe); ///< Sets if the Tag can be written as Attribute
    void setIsValueArray(bool isVarray);///< Sets if the tag contains anonymous values
    void setCanBeAttributeRecursive(bool canBe); ///< sets canBeAttribute for itself and it's children

protected:
        std::vector<Tag*> children;                     ///< All children that this tag holds
        Tag* parent;                                            ///< The Tag that contains this tag, NULL if this is the motherTag
        String name;                                            ///< The name of the Tag
        String value;                                           ///< The value that is saved inside the Tag.
        int level;                                                      ///< Determins the Number of tabs infront of a tag
        bool isComment;                                         ///< If it's true the Tag will be written as Comment.
        bool canBeAttribute;                            ///< If it's false it will never be written as Argument TODO move to XmlWriter
        bool isValueArray;                  ///< Does this Tag contain namesless values? This Boolean will tell us.

        inline void writeAsXmlAttribute(std::ostream& file); ///< Writes this Tag as Xml-Attribute to a fstream

        ///////////////////////////////////////////////////////////////////////////
        //
        // overloaded templates
        //
        ///////////////////////////////////////////////////////////////////////////

    template<typename T> T getValueAs(identity<T>)
        {
        std::stringstream ss(value);
                T ret;
                ss >> ret;
                return ret;
        }

    bool getValueAs(identity<bool>)
        {
                return this->getBooleanValue();
        }

    const char* getValueAs(identity<const char*>)
        {
                return this->value.c_str();
        }

    String getValueAs(identity<String>)
        {
                return this->value;
        }

    char getValueAs(identity<char>)
        {
                return this->getValueAs(identity<short>());
        }

    unsigned char getValueAs(identity<unsigned char>)
        {
                return this->getValueAs(identity<short>());
        }

    signed char getValueAs(identity<signed char>)
        {
                return this->getValueAs(identity<short>());
        }

};

}  // namespace nw
#endif /* TAG_H_ */