{#
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 is the template that is used to generate headers for property classes.

REUSE-IgnoreStart
#}
// 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.h.j2.
// To regenerate, run `tools/propertygenerator/generate_properties.py`.
{# REUSE-IgnoreEnd #}

#pragma once

{#
The include list may contain extra newlines that are hard to get rid of with the
template but that clang format doesn't like, so disable format for that.
#}
// clang-format off

#include <QDebug>

{% for include in system_includes | sort %}
#include <{{ include }}>
{% endfor %}

{% for include in local_includes | sort %}
#include "{{ include }}"
{% endfor %}

#include "PropertiesTypes.h"

#include "union_export.h"

// clang-format on

namespace Union
{
namespace Properties
{

class {{ type_name }}Private;

/*!
\class Union::Properties::{{ type_name }}
\inmodule core
\ingroup core-properties

{{ documentation }}
*/
class UNION_EXPORT {{ type_name }}
{
public:
    /*!
     * Default constructor. Constructs a null instance.
     *
     * A null instance in this case means an instance that does not have any
     * values for its properties. This includes property groups.
     */
    {{ type_name }}();
    /*!
     * Copy constructor.
     */
    {{ type_name }}(const {{ type_name }} &other);
    /*!
     * Move constructor.
     */
    {{ type_name }}({{ type_name }} &&other);
    ~{{ type_name }}();

    /*!
     * Copy assignment operator.
     */
    {{ type_name }} &operator=(const {{ type_name }} &other);
    /*!
     * Move assignment operator.
     */
    {{ type_name }} &operator=({{ type_name }} &&other);

{% for property in properties %}
{% if property.is_group %}
    /*!
     * Returns {{ property.name }} if set or nullptr if not.
     */
    {{ property.type }} *{{ property.name }}() const;

    /*!
     * Set the value of {{ property.name }}.
     *
     * \a newValue The new value or \c{std::nullopt} to unset the value.
     */
    void set{{ property.name | ucfirst }}(std::unique_ptr<{{ property.type }}> &&newValue);

{% else %}
    /*!
     * Returns the value of {{ property.name }}.
     */
    std::optional<{{ property.type }}> {{ property.name }}() const;

    /*!
     * Set the value of {{ property.name }}.
     *
     * \a newValue The new value or \c{std::nullopt} to unset the value.
     */
    void set{{ property.name | ucfirst }}(const std::optional<{{ property.type }}> &newValue);

{% endif %}
{% endfor %}
    /*!
     * Returns if this property group has any value set.
     *
     * Note that for any property that is also a property group, this will also
     * check if that group has any value.
     */
    bool hasAnyValue() const;

    /*!
     * Returns if this property is considered empty.
     *
     * A property is considered empty if it has no values or if the values it
     * contains are all considered empty values.
     */
    bool isEmpty() const;

    /*!
     * Returns a string representation of this property group.
     *
     * This is intended for debugging.
     *
     * \a indentation The amount of indentation to apply. Defaults to 0.
     * \a flags A set of flags that control conversion behavior.
     */
    QString toString(int indentation = 0, ToStringFlags flags = ToStringFlags{}) const;

    /*!
     * Copy property values from source to destination if destination does not have a property value.
     *
     * This will recursively copy property values of grouped properties.
     *
     * \a source      The source property group to copy from.
     * \a destination The destination property group to copy to.
     */
    static void resolveProperties(const {{ type_name }} *source, {{ type_name }} *destination);

    /*!
     * Create and return an empty {{ type_name }} instance.
     *
     * This will create an empty {{ type_name }} instance, which is defined as
     * an instance with all of its values default-constructed. Note that this is
     * different from a default-constructed instance which will have all its
     * values unset.
     */
    static std::unique_ptr<{{ type_name }}> empty();

{% if extra_code and "public" in extra_code %}
{{ extra_code["public"] | render }}

{% endif %}
private:
    std::unique_ptr<{{ type_name }}Private> d;
{% if extra_code and "private" in extra_code %}
{{ extra_code["private"] | render }}
{% endif %}
};

/*!
 * \relates Union::Properties::{{ type_name }}
 * Equality comparison for {{ type_name }}.
 */
UNION_EXPORT bool operator==(const {{ type_name }} &left, const {{ type_name}} &right);
}
}

/*!
 * \relates Union::Properties::{{ type_name }}
 * QDebug support for {{ type_name }}.
 */
UNION_EXPORT QDebug operator<<(QDebug debug, Union::Properties::{{ type_name }} *type);

UNION_EXPORT QDataStream &operator<<(QDataStream &stream, const Union::Properties::{{ type_name }} *type);
UNION_EXPORT QDataStream &operator>>(QDataStream &stream, std::unique_ptr<Union::Properties::{{ type_name }}> &type);
