/*
 * Ibis - IRCv3 Library
 * Copyright (C) 2022-2024 Ibis Developers
 *
 * Ibis is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this library; if not, see <https://www.gnu.org/licenses/>.
 */

#if !defined(IBIS_GLOBAL_HEADER_INSIDE) && !defined(IBIS_COMPILATION)
# error "only <ibis.h> may be included directly"
#endif

#ifndef IBIS_CAPABILITIES_H
#define IBIS_CAPABILITIES_H

#include <glib.h>
#include <glib-object.h>

#include "ibismessage.h"
#include "ibisversion.h"

G_BEGIN_DECLS

/**
 * IbisCapabilities:
 *
 * An object that handles capability negotiation.
 *
 * Since: 0.1
 */

#define IBIS_TYPE_CAPABILITIES (ibis_capabilities_get_type())

IBIS_AVAILABLE_IN_0_1
G_DECLARE_FINAL_TYPE(IbisCapabilities, ibis_capabilities,
                     IBIS, CAPABILITIES, GObject)

#include "ibisclient.h"

/**
 * ibis_capabilities_new:
 *
 * Creates a new capabilities object.
 *
 * Returns: (transfer full): The new instance.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
IbisCapabilities *ibis_capabilities_new(void);

/**
 * ibis_capabilities_start:
 * @client: the client instance
 *
 * Starts capability negotiation on @client.
 *
 * This will send the `CAP LS` command.
 *
 * While negotiating, you may call [method@Capabilities.add_wait] to add a wait
 * counter that will delay the sending of the `CAP END` message. The `CAP END`
 * message will be sent once all of the wait counters have been removed via
 * matching calls to [method@Capabilities.remove_wait].
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
void ibis_capabilities_start(IbisCapabilities *capabilities, IbisClient *client);

/**
 * ibis_capabilities_request:
 * @capability: the capabilities to request
 *
 * Requests @capability from the server.
 *
 * This sends the `CAP REQ` command to the server. Emits the signals
 * [signal@Capabilities::ack] or [signal@Capabilities::nak] with the requested
 * @capability as reply.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
void ibis_capabilities_request(IbisCapabilities *capabilities, const char *capability);

/**
 * ibis_capabilities_lookup:
 * @name: the name of the capability to look for
 * @found: (out) (nullable): a return address for a boolean on whether the
 *         capability was advertised or not
 *
 * Gets the value that the @name capability provided if it was advertised.
 *
 * To determine if the capability was advertised use the @found parameter.
 *
 * Returns: The value of the capability named @name.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
const char *ibis_capabilities_lookup(IbisCapabilities *capabilities, const char *name, gboolean *found);

/**
 * ibis_capabilities_lookup_and_request:
 * @name: the name of the capability to look for
 *
 * Calls [method@Capabilities.lookup] and if the capability was found, calls
 * [method@Capabilities.request].
 *
 * This method ignores the advertised value, so to get that you'll need to call
 * [method@Capabilities.lookup] yourself.
 *
 * Also if you need to do something when the server ACK's or NAK's your
 * request, you're probably better off just using the methods yourself.
 *
 * Returns: true if @name was found and requested; false otherwise.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
gboolean ibis_capabilities_lookup_and_request(IbisCapabilities *capabilities, const char *name);

/**
 * ibis_capabilities_add_wait:
 *
 * Adds a wait counter to @capabilities.
 *
 * This counter is used to delay the call of `CAP END` until all capability
 * negotiation has completed. This is necessary for SASL and may be necessary
 * for other capabilities as well.
 *
 * Since 0.11 this method will do nothing if called after
 * [signal@Capabilities::done] has been emitted.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
void ibis_capabilities_add_wait(IbisCapabilities *capabilities);

/**
 * ibis_capabilities_remove_wait:
 *
 * Removes a wait counter from @capabilities.
 *
 * Only when this counter reaches 0, will `CAP END` be called and registration
 * completed. This is necessary for SASL and may be necessary for other
 * capabilities as well.
 *
 * Since 0.11 this method will do nothing if called after
 * [signal@Capabilities::done] has been emitted.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
void ibis_capabilities_remove_wait(IbisCapabilities *capabilities);

/**
 * ibis_capabilities_stop:
 *
 * Stops handling capability commands.
 *
 * This is the opposite of [method@Capabilities.start] and should not need to
 * be called outside of Ibis.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
void ibis_capabilities_stop(IbisCapabilities *capabilities);

G_END_DECLS

#endif /* IBIS_CAPABILITIES_H */
