#include "XmlElement.h"

#include "XmlAttribute.h"

XmlElement::XmlElement(const std::string& tagName)
    : mTagName(tagName),
      mChildren()
{

}

XmlElement::~XmlElement()
{

}

XmlElementPtr XmlElement::Create(const std::string& tagName)
{
    return std::make_unique<XmlElement>(tagName);
}

void XmlElement::setTagName(const std::string& tagName)
{
    mTagName = tagName;
}

void XmlElement::addChild(XmlElementPtr child)
{
    mChildren.push_back(std::move(child));
}

void XmlElement::addAttribute(XmlAttributePtr attribute)
{
    mAttributes.push_back(std::move(attribute));
}

const std::string& XmlElement::getTagName() const
{
    return mTagName;
}

const std::string& XmlElement::getText() const
{
    return mText;
}

void XmlElement::setText(const std::string& text)
{
    mText = text;
}

XmlElement* XmlElement::getFirstChildWithTagName(const std::string& tag)
{
    for(auto& child : mChildren)
    {
        if (child->getTagName() == tag)
        {
            return child.get();
        }
    }

    return nullptr;
}

XmlAttribute* XmlElement::getAttribute(const std::string& attributeName) const
{
    for(const auto& attribute : mAttributes)
    {
        if(attribute->getName() == attributeName)
        {
            return attribute.get();
        }
    }
    return nullptr;
}

XmlAttribute* XmlElement::getAttribute(std::size_t index) const
{
    if(index < mAttributes.size())
    {
        return mAttributes[index].get();
    }
    return nullptr;
}

std::size_t XmlElement::getNumAttributes() const
{
    return mAttributes.size();
}

std::size_t XmlElement::getNumChildren() const
{
    return mChildren.size();
}

XmlElement* XmlElement::getChild(std::size_t index) const
{
    return mChildren[index].get();
}

std::string XmlElement::toString(unsigned depth, bool keepInline) const
{
    const auto prefix = std::string(2*depth, ' ');

    std::string line_ending = keepInline ? "" : "\n";

    auto content = prefix + "<" + getTagName();
    for (std::size_t idx=0; idx< getNumAttributes(); idx++)
    {
        auto attribute = getAttribute(idx);
        content += " " + attribute->getName() + "=\"" + attribute->getValue() + "\"";
    }

    const auto num_children = getNumChildren();
    if (num_children == 0 && getText().empty())
    {
        content += "/>" + line_ending;
        return content;
    }
    else
    {
        content += ">";
    }

    if (!getText().empty())
    {
        content += getText();
    }

    if (num_children>0)
    {
        content += line_ending;
    }
    for (std::size_t idx=0; idx< getNumChildren(); idx++)
    {
        auto child = getChild(idx);
        content += child->toString(depth+1, keepInline);
    }
    if (num_children>0)
    {
        content += prefix;
    }

    content += "</" + getTagName() + ">" + line_ending;
    return content;
}
