/*
 * Ibis - IRCv3 Library
 * Copyright (C) 2022-2024 Ibis Developers <devel@pidgin.im>
 *
 * 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_MESSAGE_H
#define IBIS_MESSAGE_H

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

#include "ibisctcpmessage.h"
#include "ibistags.h"
#include "ibisversion.h"

G_BEGIN_DECLS

#define IBIS_MESSAGE_PARSE_ERROR \
	(g_quark_from_static_string("ibis-message-parse-error")) \
	IBIS_AVAILABLE_MACRO_IN_0_1

#define IBIS_TYPE_MESSAGE (ibis_message_get_type())

/**
 * IbisMessage:
 *
 * A representation of an IRCv3 message.
 *
 * Since: 0.1
 */

IBIS_AVAILABLE_IN_0_1
G_DECLARE_FINAL_TYPE(IbisMessage, ibis_message, IBIS, MESSAGE, GObject)

#include "ibisstandardreply.h"

/**
 * ibis_message_new:
 * @command: (not nullable): the command of the message
 *
 * Creates a new message with @command.
 *
 * Returns: (transfer full): The new message.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
IbisMessage *ibis_message_new(const char *command);

/**
 * ibis_message_get_command:
 *
 * Gets the command of the message.
 *
 * Returns: The command of the message.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
const char *ibis_message_get_command(IbisMessage *message);

/**
 * ibis_message_get_command_quark:
 *
 * Gets the #GQuark for @message.
 *
 * This value is used when emitting signals like [signal@Client::message] and
 * isn't typically needed outside of Ibis itself.
 *
 * Returns: The quark.
 *
 * Since: 0.4
 */
IBIS_AVAILABLE_IN_0_4
GQuark ibis_message_get_command_quark(IbisMessage *message);

/**
 * ibis_message_get_ctcp:
 *
 * Checks whether @message is a CTCP message.
 *
 * This should only ever return %TRUE if the command property of @message is
 * `PRIVMSG` or `NOTICE`.
 *
 * Returns: true if @message is a CTCP message; false otherwise.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
gboolean ibis_message_get_ctcp(IbisMessage *message);

/**
 * ibis_message_get_ctcp_message:
 *
 * Gets the [class@CTCPMessage] from @message.
 *
 * Returns: (transfer none) (nullable): The `CTCP` message if set.
 *
 * Since: 0.5
 */
IBIS_AVAILABLE_IN_0_5
IbisCTCPMessage *ibis_message_get_ctcp_message(IbisMessage *message);

/**
 * ibis_message_set_ctcp_message:
 * @ctcp_message: (transfer none) (nullable): the `CTCP` message instance
 *
 * Sets the `CTCP` message of @message to @ctcp_message.
 *
 * Since: 0.5
 */
IBIS_AVAILABLE_IN_0_5
void ibis_message_set_ctcp_message(IbisMessage *message, IbisCTCPMessage *ctcp_message);

/**
 * ibis_message_set_ctcp:
 * @ctcp: if true make this a CTCP message
 *
 * Sets @message to be a CTCP message or not.
 *
 * > Note: If the command of @message is not `PRIVMSG` or `NOTICE` this method
 * will have no effect.
 *
 * Since: 0.1
 *
 * Deprecated: 0.5
 */
IBIS_DEPRECATED_FOR(ibis_message_set_ctcp_message)
void ibis_message_set_ctcp(IbisMessage *message, gboolean ctcp);

/**
 * ibis_message_get_params:
 *
 * Gets the parameters from @message.
 *
 * Returns: (transfer none) (nullable): The parameters from @message.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
GStrv ibis_message_get_params(IbisMessage *message);

/**
 * ibis_message_set_params:
 * @...: a list of parameters to add followed by %NULL
 *
 * Sets the parameters of @message.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
void ibis_message_set_params(IbisMessage *message, ...) G_GNUC_NULL_TERMINATED;

/**
 * ibis_message_set_paramsv: (rename-to ibis_message_set_params):
 * @params: (transfer none) (nullable): the new parameters
 *
 * Sets the parameters of @message to @params.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
void ibis_message_set_paramsv(IbisMessage *message, GStrv params);

/**
 * ibis_message_get_source:
 *
 * Gets the source of @message.
 *
 * Returns: (nullable): The source of @message.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
const char *ibis_message_get_source(IbisMessage *message);

/**
 * ibis_message_set_source:
 * @source: (nullable): the new source
 *
 * Sets the source of @message to @source.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
void ibis_message_set_source(IbisMessage *message, const char *source);

/**
 * ibis_message_get_tags:
 *
 * Gets the tags from @message.
 *
 * Returns: (transfer none) (nullable): The tags from @message.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
IbisTags *ibis_message_get_tags(IbisMessage *message);

/**
 * ibis_message_set_tags:
 * @tags: (transfer none) (nullable): the new tags
 *
 * Sets the tags of @message to @tags.
 *
 * Since: 0.1
 *
 * Deprecated: 0.10: Use [method@Message.get_tags] and update that directly.
 */
IBIS_DEPRECATED
void ibis_message_set_tags(IbisMessage *message, IbisTags *tags);

/**
 * ibis_message_get_timestamp:
 *
 * Gets the value of the @time tag if it exists.
 *
 * Returns: (transfer full) (nullable): The timestamp.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
GDateTime *ibis_message_get_timestamp(IbisMessage *message);

/**
 * ibis_message_serialize:
 * @include_tags: if true tags will be included
 *
 * Serializes @message into a [type@GLib.Bytes].
 *
 * If @include_tags is %FALSE, the tags will not be added to the output. This
 * only should be set %TRUE if the message-tags capability has been negotiated
 * with the server.
 *
 * This output does include the trailing `\r\n`.
 *
 * Returns: (transfer full): The serialized message.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
GBytes *ibis_message_serialize(IbisMessage *message, gboolean include_tags);

/**
 * ibis_message_serialize_to_string:
 * @include_tags: if true tags will be included
 *
 * Serializes @message into a string.
 *
 * If @include_tags is %FALSE, the tags will not be added to the output. This
 * only should be set %TRUE if the message-tags capability has been negotiated
 * with the server.
 *
 * This string does include the trailing `\r\n`.
 *
 * Returns: (transfer full): The serialized message.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
char *ibis_message_serialize_to_string(IbisMessage *message, gboolean include_tags);

/**
 * ibis_message_get_error:
 *
 * Gets the error for @message.
 *
 * Errors are typically set on messages when they are being parsed and
 * something isn't right.
 *
 * Returns: (transfer none) (nullable): The error if one is set.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
GError *ibis_message_get_error(IbisMessage *message);

/**
 * ibis_message_set_error:
 * @error: (nullable) (transfer none): the new error message
 *
 * Sets the error for @message to @error.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
void ibis_message_set_error(IbisMessage *message, GError *error);

/**
 * ibis_message_take_error:
 * @error: (nullable) (transfer full): the new error message
 *
 * Sets the error for @message to @error taking ownership of @error.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
void ibis_message_take_error(IbisMessage *message, GError *error);

/**
 * ibis_message_parse:
 * @buffer: the raw IRC message
 * @error: (nullable): return address for a #GError
 *
 * Attempts to parse a raw IRC message from @buffer.
 *
 * @buffer should not have the trailing `\r\n`.
 *
 * This will call [func@GLib.utf8_make_valid] on @buffer. If any invalid
 * characters are found they will be converted into the
 * [Unicode Replacement Character](https://en.wikipedia.org/wiki/Specials_(Unicode_block)#Replacement_character)
 * (0xEF 0xBF 0xBD in UTF-8). The replacement characters can end up in any
 * property of the return message and it is up to the caller to determine what
 * to do with the replacement characters.
 *
 * Returns: (transfer full) (nullable): The new message if one was parsed.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
IbisMessage *ibis_message_parse(const char *buffer, GError **error);

/**
 * ibis_message_get_raw_message:
 *
 * Gets the `raw-message` that @message was parsed from.
 *
 * If @message was not created via [func@Message.parse], then this will be
 * %NULL.
 *
 * Returns: (nullable): The raw message if available.
 *
 * Since: 0.1
 */
IBIS_AVAILABLE_IN_0_1
const char *ibis_message_get_raw_message(IbisMessage *message);

/**
 * ibis_message_is_command:
 * @command: (nullable): the command to check
 *
 * Checks if [property@Message:command] is @command.
 *
 * Note: No additional normalization will be performed. But commands are
 *       normalized to upper case when they are parsed, and if you use the
 *       constants everything should be already normalized.
 *
 * Returns: true if the command of @message matches @command; false otherwise.
 *
 *
 * Since: 0.7
 */
IBIS_AVAILABLE_IN_0_7
gboolean ibis_message_is_command(IbisMessage *message, const char *command);

/**
 * ibis_message_get_standard_reply:
 *
 * Gets the [class@StandardReply] from @message.
 *
 * Returns: (transfer none) (nullable): The standard reply if @message contains one.
 *
 * Since: 0.8
 */
IBIS_AVAILABLE_IN_0_8
IbisStandardReply *ibis_message_get_standard_reply(IbisMessage *message);

G_END_DECLS

#endif /* IBIS_MESSAGE_H */
