// 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 "AlignmentProperty.h"

#include <QRegularExpression>

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

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

class Union::Properties::AlignmentPropertyPrivate
{
public:
    std::optional<Union::Properties::AlignmentContainer> container;
    std::optional<Union::Properties::Alignment> horizontal;
    std::optional<Union::Properties::Alignment> vertical;
    std::optional<int> order;
};

AlignmentProperty::AlignmentProperty()
    : d(std::make_unique<AlignmentPropertyPrivate>())
{
}

AlignmentProperty::AlignmentProperty(const AlignmentProperty &other)
    : d(std::make_unique<AlignmentPropertyPrivate>())
{
    d->container = other.d->container;
    d->horizontal = other.d->horizontal;
    d->vertical = other.d->vertical;
    d->order = other.d->order;
}

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

AlignmentProperty::~AlignmentProperty() = default;

AlignmentProperty &AlignmentProperty::operator=(const AlignmentProperty &other)
{
    if (this != &other) {
        d->container = other.d->container;
        d->horizontal = other.d->horizontal;
        d->vertical = other.d->vertical;
        d->order = other.d->order;
    }
    return *this;
}

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

std::optional<Union::Properties::AlignmentContainer> AlignmentProperty::container() const
{
    return d->container;
}

void AlignmentProperty::setContainer(const std::optional<Union::Properties::AlignmentContainer> &newValue)
{
    if (newValue == d->container) {
        return;
    }

    d->container = newValue;
}

std::optional<Union::Properties::Alignment> AlignmentProperty::horizontal() const
{
    return d->horizontal;
}

void AlignmentProperty::setHorizontal(const std::optional<Union::Properties::Alignment> &newValue)
{
    if (newValue == d->horizontal) {
        return;
    }

    d->horizontal = newValue;
}

std::optional<Union::Properties::Alignment> AlignmentProperty::vertical() const
{
    return d->vertical;
}

void AlignmentProperty::setVertical(const std::optional<Union::Properties::Alignment> &newValue)
{
    if (newValue == d->vertical) {
        return;
    }

    d->vertical = newValue;
}

std::optional<int> AlignmentProperty::order() const
{
    return d->order;
}

void AlignmentProperty::setOrder(const std::optional<int> &newValue)
{
    if (newValue == d->order) {
        return;
    }

    d->order = newValue;
}

bool AlignmentProperty::hasAnyValue() const
{
    if (d->container.has_value()) {
        return true;
    }
    if (d->horizontal.has_value()) {
        return true;
    }
    if (d->vertical.has_value()) {
        return true;
    }
    if (d->order.has_value()) {
        return true;
    }
    return false;
}

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

    if (d->container.has_value() && d->container.value() != emptyValue<Union::Properties::AlignmentContainer>()) {
        return false;
    }
    if (d->horizontal.has_value() && d->horizontal.value() != emptyValue<Union::Properties::Alignment>()) {
        return false;
    }
    if (d->vertical.has_value() && d->vertical.value() != emptyValue<Union::Properties::Alignment>()) {
        return false;
    }
    if (d->order.has_value() && d->order.value() != emptyValue<int>()) {
        return false;
    }

    return true;
}

QString AlignmentProperty::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 << "AlignmentProperty(" << maybeNewLine;
    } else if (indentation > 0) {
        out << maybeNewLine;
    }

    out << indent(indentation, multiline, true) << "container: ";
    if (d->container) {
        out << d->container.value() << maybeNewLine;
    } else {
        out << empty << maybeNewLine;
    }
    out << indent(indentation, multiline, false) << "horizontal: ";
    if (d->horizontal) {
        out << d->horizontal.value() << maybeNewLine;
    } else {
        out << empty << maybeNewLine;
    }
    out << indent(indentation, multiline, false) << "vertical: ";
    if (d->vertical) {
        out << d->vertical.value() << maybeNewLine;
    } else {
        out << empty << maybeNewLine;
    }
    out << indent(indentation, multiline, false) << "order: ";
    if (d->order) {
        out << d->order.value() << maybeNewLine;
    } else {
        out << empty << maybeNewLine;
    }

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

    out.flush();

    return result;
}

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

    if (!destination->d->container.has_value()) {
        destination->d->container = source->d->container;
    }
    if (!destination->d->horizontal.has_value()) {
        destination->d->horizontal = source->d->horizontal;
    }
    if (!destination->d->vertical.has_value()) {
        destination->d->vertical = source->d->vertical;
    }
    if (!destination->d->order.has_value()) {
        destination->d->order = source->d->order;
    }
}

std::unique_ptr<AlignmentProperty> AlignmentProperty::empty()
{
    auto result = std::make_unique<AlignmentProperty>();
    result->d->container = emptyValue<Union::Properties::AlignmentContainer>();
    result->d->horizontal = emptyValue<Union::Properties::Alignment>();
    result->d->vertical = emptyValue<Union::Properties::Alignment>();
    result->d->order = emptyValue<int>();
    return result;
}

bool Union::Properties::operator==(const AlignmentProperty &left, const AlignmentProperty &right)
{
    if (left.container() != right.container()) {
        return false;
    }
    if (left.horizontal() != right.horizontal()) {
        return false;
    }
    if (left.vertical() != right.vertical()) {
        return false;
    }
    if (left.order() != right.order()) {
        return false;
    }
    return true;
}

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

QDataStream &operator<<(QDataStream &stream, const Union::Properties::AlignmentProperty *type)
{
    stream << type->container();
    stream << type->horizontal();
    stream << type->vertical();
    stream << type->order();
    return stream;
}

QDataStream &operator>>(QDataStream &stream, std::unique_ptr<Union::Properties::AlignmentProperty> &type)
{
    {
        std::optional<Union::Properties::AlignmentContainer> data;
        stream >> data;
        type->setContainer(data);
    }
    {
        std::optional<Union::Properties::Alignment> data;
        stream >> data;
        type->setHorizontal(data);
    }
    {
        std::optional<Union::Properties::Alignment> data;
        stream >> data;
        type->setVertical(data);
    }
    {
        std::optional<int> data;
        stream >> data;
        type->setOrder(data);
    }

    return stream;
}