/*
    This file is part of libkldap.
    SPDX-FileCopyrightText: 2004-2006 Szombathelyi György <gyurco@freemail.hu>

    SPDX-License-Identifier: LGPL-2.0-or-later
*/

#pragma once

#include <QStringList>

#include <QUrl>

#include "kldap_core_export.h"
#include "ldapdn.h"

// clazy:excludeall=copyable-polymorphic

namespace KLDAPCore
{
/*!
 * \class KLDAPCore::LdapUrl
 * \inmodule LdapCore
 * \inheaderfile KLDAPCore/LdapUrl
 *
 * \brief A special url class for LDAP.
 *
 * LdapUrl implements an RFC 2255 compliant LDAP Url parser, with minimal
 * differences. LDAP Urls implemented by this class has the following format:
 * ldap[s]://[user[:password]@]hostname[:port]["/" [dn ["?" [attributes]
 * ["?" [scope] ["?" [filter] ["?" extensions]]]]]]
 */
class KLDAP_CORE_EXPORT LdapUrl : public QUrl
{
public:
    /*!
     * A class holding the extension name and state whether
     * the extension is critical.
     */
    using Extension = struct {
        QString value;
        bool critical;
    };

    /*!
     * Describes the scope of the LDAP url.
     */
    using Scope = enum {
        Base, ///< Only the same level as the url.
        One, ///< The level of the url and the one below.
        Sub ///< All levels below the url's level.
    };

    /*!
     * Constructs an empty LDAP URL.
     */
    LdapUrl();

    /*!
     * Constructs an LDAP URL from a QUrl.
     * \param url the QUrl to construct from
     */
    explicit LdapUrl(const QUrl &url);

    /*!
     * Constructs a copy of the given LDAP URL.
     * \param other the LDAP URL to copy
     */
    LdapUrl(const LdapUrl &other);

    /*!
     * Assigns the values from another LDAP URL to this URL.
     * \param other the LDAP URL to assign
     * \return a reference to this URL
     */
    LdapUrl &operator=(const LdapUrl &other);

    /*!
     * Destroys the LDAP URL.
     */
    ~LdapUrl();

    /*!
     * Sets the DN part of the LDAP URL.
     * \param dn the DN to set
     */
    void setDn(const LdapDN &dn);

    /*!
     * Returns the DN part of the LDAP URL.
     * This is equal to path() with the slash removed from the beginning.
     * \return the DN part of the URL
     */
    [[nodiscard]] LdapDN dn() const;

    /*!
     * Sets the attributes part of the LDAP URL.
     * \param attributes the list of attributes to set
     */
    void setAttributes(const QStringList &attributes);

    /*!
     * Returns the attributes part of the LDAP URL.
     * \return the list of attributes
     */
    [[nodiscard]] QStringList attributes() const;

    /*!
     * Sets the scope part of the LDAP URL.
     * \param scope the scope to set
     */
    void setScope(Scope scope);

    /*!
     * Returns the scope part of the LDAP URL.
     * \return the scope
     */
    [[nodiscard]] Scope scope() const;

    /*!
     * Sets the filter part of the LDAP URL.
     * \param filter the filter string to set
     */
    void setFilter(const QString &filter);

    /*!
     * Returns the filter part of the LDAP URL.
     * \return the filter string
     */
    [[nodiscard]] QString filter() const;

    /*!
     * Returns whether the specified extension exists in the LDAP URL.
     * \param extension the extension name
     * \return true if the extension exists
     */
    [[nodiscard]] bool hasExtension(const QString &extension) const;

    /*!
     * Returns the specified extension.
     * \param extension the extension name
     * \return the extension value
     */
    [[nodiscard]] Extension extension(const QString &extension) const;

    /*!
     * Returns the specified extension value and criticality flag.
     * \param extension the extension name
     * \param critical output parameter for the criticality flag
     * \return the extension value
     */
    [[nodiscard]] QString extension(const QString &extension, bool &critical) const;

    /*!
     * Sets the specified extension with the given value and criticality.
     * \param key the extension name
     * \param extension the extension value and criticality
     */
    void setExtension(const QString &key, const Extension &extension);

    /*!
     * Sets the specified extension with the given string value and criticality.
     * \param key the extension name
     * \param value the extension value
     * \param critical whether the extension is critical
     */
    void setExtension(const QString &key, const QString &value, bool critical = false);

    /*!
     * Sets the specified extension with the given integer value and criticality.
     * \param key the extension name
     * \param value the extension value
     * \param critical whether the extension is critical
     */
    void setExtension(const QString &key, int value, bool critical = false);

    /*!
     * Removes the specified extension.
     * \param extension the extension name to remove
     */
    void removeExtension(const QString &extension);

    /*!
     * Updates the query component from the attributes, scope, filter and extensions.
     */
    void updateQuery();

    /*!
     * Parses the query argument of the URL and makes it available via the
     * attributes(), extension(), filter() and scope() methods.
     */
    void parseQuery();

private:
    class LdapUrlPrivate;
    std::unique_ptr<LdapUrlPrivate> const d;
};
}
