// SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
// SPDX-FileCopyrightText: 2024 Arjen Hiemstra <ahiemstra@heimr.nl>
//
// This file is automatically generated from property.cpp.j2.
// To regenerate, run `tools/propertygenerator/generate_properties.py`.

#include "StylePropertyGroup.h"

#include <QRegularExpression>

#include "PropertiesTypes.h"
#include "QDataStreamExtras.h"

using namespace Union::Properties;
using namespace Qt::StringLiterals;

class Union::Properties::StylePropertyGroupPrivate
{
public:
    std::unique_ptr<DisplayPropertyGroup> display;
    std::unique_ptr<LayoutPropertyGroup> layout;
    std::unique_ptr<TextPropertyGroup> text;
    std::unique_ptr<IconPropertyGroup> icon;
    std::unique_ptr<BackgroundPropertyGroup> background;
    std::unique_ptr<BorderPropertyGroup> border;
    std::unique_ptr<OutlinePropertyGroup> outline;
    std::unique_ptr<CornersPropertyGroup> corners;
    std::unique_ptr<ShadowPropertyGroup> shadow;
};

StylePropertyGroup::StylePropertyGroup()
    : d(std::make_unique<StylePropertyGroupPrivate>())
{
}

StylePropertyGroup::StylePropertyGroup(const StylePropertyGroup &other)
    : d(std::make_unique<StylePropertyGroupPrivate>())
{
    d->display = std::make_unique<DisplayPropertyGroup>();
    *(d->display) = *(other.d->display);
    d->layout = std::make_unique<LayoutPropertyGroup>();
    *(d->layout) = *(other.d->layout);
    d->text = std::make_unique<TextPropertyGroup>();
    *(d->text) = *(other.d->text);
    d->icon = std::make_unique<IconPropertyGroup>();
    *(d->icon) = *(other.d->icon);
    d->background = std::make_unique<BackgroundPropertyGroup>();
    *(d->background) = *(other.d->background);
    d->border = std::make_unique<BorderPropertyGroup>();
    *(d->border) = *(other.d->border);
    d->outline = std::make_unique<OutlinePropertyGroup>();
    *(d->outline) = *(other.d->outline);
    d->corners = std::make_unique<CornersPropertyGroup>();
    *(d->corners) = *(other.d->corners);
    d->shadow = std::make_unique<ShadowPropertyGroup>();
    *(d->shadow) = *(other.d->shadow);
}

StylePropertyGroup::StylePropertyGroup(StylePropertyGroup &&other)
    : d(std::move(other.d))
{
}

StylePropertyGroup::~StylePropertyGroup() = default;

StylePropertyGroup &StylePropertyGroup::operator=(const StylePropertyGroup &other)
{
    if (this != &other) {
        *(d->display) = *(other.d->display);
        *(d->layout) = *(other.d->layout);
        *(d->text) = *(other.d->text);
        *(d->icon) = *(other.d->icon);
        *(d->background) = *(other.d->background);
        *(d->border) = *(other.d->border);
        *(d->outline) = *(other.d->outline);
        *(d->corners) = *(other.d->corners);
        *(d->shadow) = *(other.d->shadow);
    }
    return *this;
}

StylePropertyGroup &StylePropertyGroup::operator=(StylePropertyGroup &&other)
{
    std::swap(d, other.d);
    return *this;
}

DisplayPropertyGroup *StylePropertyGroup::display() const
{
    return d->display.get();
}

void StylePropertyGroup::setDisplay(std::unique_ptr<DisplayPropertyGroup> &&newValue)
{
    d->display = std::move(newValue);
}

LayoutPropertyGroup *StylePropertyGroup::layout() const
{
    return d->layout.get();
}

void StylePropertyGroup::setLayout(std::unique_ptr<LayoutPropertyGroup> &&newValue)
{
    d->layout = std::move(newValue);
}

TextPropertyGroup *StylePropertyGroup::text() const
{
    return d->text.get();
}

void StylePropertyGroup::setText(std::unique_ptr<TextPropertyGroup> &&newValue)
{
    d->text = std::move(newValue);
}

IconPropertyGroup *StylePropertyGroup::icon() const
{
    return d->icon.get();
}

void StylePropertyGroup::setIcon(std::unique_ptr<IconPropertyGroup> &&newValue)
{
    d->icon = std::move(newValue);
}

BackgroundPropertyGroup *StylePropertyGroup::background() const
{
    return d->background.get();
}

void StylePropertyGroup::setBackground(std::unique_ptr<BackgroundPropertyGroup> &&newValue)
{
    d->background = std::move(newValue);
}

BorderPropertyGroup *StylePropertyGroup::border() const
{
    return d->border.get();
}

void StylePropertyGroup::setBorder(std::unique_ptr<BorderPropertyGroup> &&newValue)
{
    d->border = std::move(newValue);
}

OutlinePropertyGroup *StylePropertyGroup::outline() const
{
    return d->outline.get();
}

void StylePropertyGroup::setOutline(std::unique_ptr<OutlinePropertyGroup> &&newValue)
{
    d->outline = std::move(newValue);
}

CornersPropertyGroup *StylePropertyGroup::corners() const
{
    return d->corners.get();
}

void StylePropertyGroup::setCorners(std::unique_ptr<CornersPropertyGroup> &&newValue)
{
    d->corners = std::move(newValue);
}

ShadowPropertyGroup *StylePropertyGroup::shadow() const
{
    return d->shadow.get();
}

void StylePropertyGroup::setShadow(std::unique_ptr<ShadowPropertyGroup> &&newValue)
{
    d->shadow = std::move(newValue);
}

bool StylePropertyGroup::hasAnyValue() const
{
    if (d->display && d->display->hasAnyValue()) {
        return true;
    }
    if (d->layout && d->layout->hasAnyValue()) {
        return true;
    }
    if (d->text && d->text->hasAnyValue()) {
        return true;
    }
    if (d->icon && d->icon->hasAnyValue()) {
        return true;
    }
    if (d->background && d->background->hasAnyValue()) {
        return true;
    }
    if (d->border && d->border->hasAnyValue()) {
        return true;
    }
    if (d->outline && d->outline->hasAnyValue()) {
        return true;
    }
    if (d->corners && d->corners->hasAnyValue()) {
        return true;
    }
    if (d->shadow && d->shadow->hasAnyValue()) {
        return true;
    }
    return false;
}

bool StylePropertyGroup::isEmpty() const
{
    if (!hasAnyValue()) {
        return true;
    }

    if (d->display && !d->display->isEmpty()) {
        return false;
    }
    if (d->layout && !d->layout->isEmpty()) {
        return false;
    }
    if (d->text && !d->text->isEmpty()) {
        return false;
    }
    if (d->icon && !d->icon->isEmpty()) {
        return false;
    }
    if (d->background && !d->background->isEmpty()) {
        return false;
    }
    if (d->border && !d->border->isEmpty()) {
        return false;
    }
    if (d->outline && !d->outline->isEmpty()) {
        return false;
    }
    if (d->corners && !d->corners->isEmpty()) {
        return false;
    }
    if (d->shadow && !d->shadow->isEmpty()) {
        return false;
    }

    return true;
}

QString StylePropertyGroup::toString(int indentation, ToStringFlags flags) const
{
    if (!hasAnyValue()) {
        return u"(empty)"_s;
    }

    const bool multiline = flags & ToStringFlag::MultiLine;
    const bool types = flags & ToStringFlag::Types;

    QString result;
    QTextStream out(&result);

    constexpr auto indent = [](int amount, bool multiline, bool first) {
        if (multiline) {
            return QByteArray(amount, ' ');
        } else if (!first) {
            return QByteArray(", ");
        } else {
            return QByteArray(" ");
        }
    };

    const QByteArray maybeNewLine = multiline ? "\n" : "";
    const QByteArray empty = "(empty)";

    if (types) {
        out << "StylePropertyGroup(" << maybeNewLine;
    } else if (indentation > 0) {
        out << maybeNewLine;
    }

    out << indent(indentation, multiline, true) << "display: ";
    if (d->display) {
        out << d->display->toString(indentation + 2, flags);
    } else {
        out << empty << maybeNewLine;
    }
    out << indent(indentation, multiline, false) << "layout: ";
    if (d->layout) {
        out << d->layout->toString(indentation + 2, flags);
    } else {
        out << empty << maybeNewLine;
    }
    out << indent(indentation, multiline, false) << "text: ";
    if (d->text) {
        out << d->text->toString(indentation + 2, flags);
    } else {
        out << empty << maybeNewLine;
    }
    out << indent(indentation, multiline, false) << "icon: ";
    if (d->icon) {
        out << d->icon->toString(indentation + 2, flags);
    } else {
        out << empty << maybeNewLine;
    }
    out << indent(indentation, multiline, false) << "background: ";
    if (d->background) {
        out << d->background->toString(indentation + 2, flags);
    } else {
        out << empty << maybeNewLine;
    }
    out << indent(indentation, multiline, false) << "border: ";
    if (d->border) {
        out << d->border->toString(indentation + 2, flags);
    } else {
        out << empty << maybeNewLine;
    }
    out << indent(indentation, multiline, false) << "outline: ";
    if (d->outline) {
        out << d->outline->toString(indentation + 2, flags);
    } else {
        out << empty << maybeNewLine;
    }
    out << indent(indentation, multiline, false) << "corners: ";
    if (d->corners) {
        out << d->corners->toString(indentation + 2, flags);
    } else {
        out << empty << maybeNewLine;
    }
    out << indent(indentation, multiline, false) << "shadow: ";
    if (d->shadow) {
        out << d->shadow->toString(indentation + 2, flags);
    } else {
        out << empty << maybeNewLine;
    }

    if (types) {
        out << indent(indentation - 2, multiline, true) << ")";
    }
    out << maybeNewLine;

    out.flush();

    return result;
}

void StylePropertyGroup::resolveProperties(const StylePropertyGroup *source, StylePropertyGroup *destination)
{
    if (!source || !destination) {
        return;
    }

    if (source->d->display) {
        if (!destination->d->display) {
            destination->d->display = std::make_unique<DisplayPropertyGroup>();
        }
        DisplayPropertyGroup::resolveProperties(source->d->display.get(), destination->d->display.get());
    }
    if (source->d->layout) {
        if (!destination->d->layout) {
            destination->d->layout = std::make_unique<LayoutPropertyGroup>();
        }
        LayoutPropertyGroup::resolveProperties(source->d->layout.get(), destination->d->layout.get());
    }
    if (source->d->text) {
        if (!destination->d->text) {
            destination->d->text = std::make_unique<TextPropertyGroup>();
        }
        TextPropertyGroup::resolveProperties(source->d->text.get(), destination->d->text.get());
    }
    if (source->d->icon) {
        if (!destination->d->icon) {
            destination->d->icon = std::make_unique<IconPropertyGroup>();
        }
        IconPropertyGroup::resolveProperties(source->d->icon.get(), destination->d->icon.get());
    }
    if (source->d->background) {
        if (!destination->d->background) {
            destination->d->background = std::make_unique<BackgroundPropertyGroup>();
        }
        BackgroundPropertyGroup::resolveProperties(source->d->background.get(), destination->d->background.get());
    }
    if (source->d->border) {
        if (!destination->d->border) {
            destination->d->border = std::make_unique<BorderPropertyGroup>();
        }
        BorderPropertyGroup::resolveProperties(source->d->border.get(), destination->d->border.get());
    }
    if (source->d->outline) {
        if (!destination->d->outline) {
            destination->d->outline = std::make_unique<OutlinePropertyGroup>();
        }
        OutlinePropertyGroup::resolveProperties(source->d->outline.get(), destination->d->outline.get());
    }
    if (source->d->corners) {
        if (!destination->d->corners) {
            destination->d->corners = std::make_unique<CornersPropertyGroup>();
        }
        CornersPropertyGroup::resolveProperties(source->d->corners.get(), destination->d->corners.get());
    }
    if (source->d->shadow) {
        if (!destination->d->shadow) {
            destination->d->shadow = std::make_unique<ShadowPropertyGroup>();
        }
        ShadowPropertyGroup::resolveProperties(source->d->shadow.get(), destination->d->shadow.get());
    }
}

std::unique_ptr<StylePropertyGroup> StylePropertyGroup::empty()
{
    auto result = std::make_unique<StylePropertyGroup>();
    result->d->display = DisplayPropertyGroup::empty();
    result->d->layout = LayoutPropertyGroup::empty();
    result->d->text = TextPropertyGroup::empty();
    result->d->icon = IconPropertyGroup::empty();
    result->d->background = BackgroundPropertyGroup::empty();
    result->d->border = BorderPropertyGroup::empty();
    result->d->outline = OutlinePropertyGroup::empty();
    result->d->corners = CornersPropertyGroup::empty();
    result->d->shadow = ShadowPropertyGroup::empty();
    return result;
}

bool Union::Properties::operator==(const StylePropertyGroup &left, const StylePropertyGroup &right)
{
    if (left.display() && right.display()) {
        if (*(left.display()) != *(right.display())) {
            return false;
        }
    } else if (left.display() != right.display()) {
        return false;
    }
    if (left.layout() && right.layout()) {
        if (*(left.layout()) != *(right.layout())) {
            return false;
        }
    } else if (left.layout() != right.layout()) {
        return false;
    }
    if (left.text() && right.text()) {
        if (*(left.text()) != *(right.text())) {
            return false;
        }
    } else if (left.text() != right.text()) {
        return false;
    }
    if (left.icon() && right.icon()) {
        if (*(left.icon()) != *(right.icon())) {
            return false;
        }
    } else if (left.icon() != right.icon()) {
        return false;
    }
    if (left.background() && right.background()) {
        if (*(left.background()) != *(right.background())) {
            return false;
        }
    } else if (left.background() != right.background()) {
        return false;
    }
    if (left.border() && right.border()) {
        if (*(left.border()) != *(right.border())) {
            return false;
        }
    } else if (left.border() != right.border()) {
        return false;
    }
    if (left.outline() && right.outline()) {
        if (*(left.outline()) != *(right.outline())) {
            return false;
        }
    } else if (left.outline() != right.outline()) {
        return false;
    }
    if (left.corners() && right.corners()) {
        if (*(left.corners()) != *(right.corners())) {
            return false;
        }
    } else if (left.corners() != right.corners()) {
        return false;
    }
    if (left.shadow() && right.shadow()) {
        if (*(left.shadow()) != *(right.shadow())) {
            return false;
        }
    } else if (left.shadow() != right.shadow()) {
        return false;
    }
    return true;
}

QDebug operator<<(QDebug debug, Union::Properties::StylePropertyGroup *type)
{
    QDebugStateSaver saver(debug);
    debug.nospace() << qPrintable(type->toString(0, ToStringFlag::Types));
    return debug;
}

QDataStream &operator<<(QDataStream &stream, const Union::Properties::StylePropertyGroup *type)
{
    {
        auto data = type->display();
        stream << bool(data);
        if (data) {
            stream << data;
        }
    }
    {
        auto data = type->layout();
        stream << bool(data);
        if (data) {
            stream << data;
        }
    }
    {
        auto data = type->text();
        stream << bool(data);
        if (data) {
            stream << data;
        }
    }
    {
        auto data = type->icon();
        stream << bool(data);
        if (data) {
            stream << data;
        }
    }
    {
        auto data = type->background();
        stream << bool(data);
        if (data) {
            stream << data;
        }
    }
    {
        auto data = type->border();
        stream << bool(data);
        if (data) {
            stream << data;
        }
    }
    {
        auto data = type->outline();
        stream << bool(data);
        if (data) {
            stream << data;
        }
    }
    {
        auto data = type->corners();
        stream << bool(data);
        if (data) {
            stream << data;
        }
    }
    {
        auto data = type->shadow();
        stream << bool(data);
        if (data) {
            stream << data;
        }
    }
    return stream;
}

QDataStream &operator>>(QDataStream &stream, std::unique_ptr<Union::Properties::StylePropertyGroup> &type)
{
    {
        bool hasData;
        stream >> hasData;

        if (hasData) {
            auto data = std::make_unique<DisplayPropertyGroup>();
            stream >> data;
            type->setDisplay(std::move(data));
        }
    }
    {
        bool hasData;
        stream >> hasData;

        if (hasData) {
            auto data = std::make_unique<LayoutPropertyGroup>();
            stream >> data;
            type->setLayout(std::move(data));
        }
    }
    {
        bool hasData;
        stream >> hasData;

        if (hasData) {
            auto data = std::make_unique<TextPropertyGroup>();
            stream >> data;
            type->setText(std::move(data));
        }
    }
    {
        bool hasData;
        stream >> hasData;

        if (hasData) {
            auto data = std::make_unique<IconPropertyGroup>();
            stream >> data;
            type->setIcon(std::move(data));
        }
    }
    {
        bool hasData;
        stream >> hasData;

        if (hasData) {
            auto data = std::make_unique<BackgroundPropertyGroup>();
            stream >> data;
            type->setBackground(std::move(data));
        }
    }
    {
        bool hasData;
        stream >> hasData;

        if (hasData) {
            auto data = std::make_unique<BorderPropertyGroup>();
            stream >> data;
            type->setBorder(std::move(data));
        }
    }
    {
        bool hasData;
        stream >> hasData;

        if (hasData) {
            auto data = std::make_unique<OutlinePropertyGroup>();
            stream >> data;
            type->setOutline(std::move(data));
        }
    }
    {
        bool hasData;
        stream >> hasData;

        if (hasData) {
            auto data = std::make_unique<CornersPropertyGroup>();
            stream >> data;
            type->setCorners(std::move(data));
        }
    }
    {
        bool hasData;
        stream >> hasData;

        if (hasData) {
            auto data = std::make_unique<ShadowPropertyGroup>();
            stream >> data;
            type->setShadow(std::move(data));
        }
    }

    return stream;
}