#include "ui_core/layout_xml.h"

#include "ui_core/layout_value.h"

#include <tinyxml2.h>

namespace pp::ui {

namespace {

[[nodiscard]] pp::foundation::Status visit_element(const tinyxml2::XMLElement& element, LayoutParseSummary& summary)
{
    ++summary.node_count;

    for (const char* name : { "width", "height" }) {
        const char* value = element.Attribute(name);
        if (value == nullptr) {
            continue;
        }

        const auto length = parse_layout_length(value);
        if (!length) {
            return length.status();
        }
        ++summary.length_attribute_count;
    }

    for (const tinyxml2::XMLElement* child = element.FirstChildElement();
         child != nullptr;
         child = child->NextSiblingElement()) {
        const auto status = visit_element(*child, summary);
        if (!status.ok()) {
            return status;
        }
    }

    return pp::foundation::Status::success();
}

}

pp::foundation::Result<LayoutParseSummary> parse_layout_xml(std::string_view xml)
{
    if (xml.empty()) {
        return pp::foundation::Result<LayoutParseSummary>::failure(
            pp::foundation::Status::invalid_argument("layout XML must not be empty"));
    }

    tinyxml2::XMLDocument document;
    const auto error = document.Parse(xml.data(), xml.size());
    if (error != tinyxml2::XML_SUCCESS) {
        return pp::foundation::Result<LayoutParseSummary>::failure(
            pp::foundation::Status::invalid_argument("layout XML could not be parsed"));
    }

    const tinyxml2::XMLElement* root = document.RootElement();
    if (root == nullptr) {
        return pp::foundation::Result<LayoutParseSummary>::failure(
            pp::foundation::Status::invalid_argument("layout XML has no root element"));
    }

    LayoutParseSummary summary;
    const auto status = visit_element(*root, summary);
    if (!status.ok()) {
        return pp::foundation::Result<LayoutParseSummary>::failure(status);
    }

    return pp::foundation::Result<LayoutParseSummary>::success(summary);
}

}
