//
//  tb_message_private.h
//  Tightbeam

#ifndef __TIGHTBEAM_MESSAGE_PRIVATE_H
#define __TIGHTBEAM_MESSAGE_PRIVATE_H

#include <sys/cdefs.h>
__ptrcheck_abi_assume_single()

#include <Tightbeam/tb_message.h>

TB_ASSUME_NONNULL_BEGIN
__TB_BEGIN_DECLS

#define TB_MESSAGE_PREAMBLE_VERS_1 1

struct tb_message_s {
	tb_message_state_t state;
	tb_message_disposition_t disposition;
	uintptr_t owning_connection_id; /* sendable messages set this value */
    uint64_t client_id;
    tb_message_identifier_t msg_id;
	uint64_t thread_id; // FIXME: (Snee) - Is this how we're going to track the owning thread?
	uint64_t capabilities[TB_MAX_CAPS];
	size_t num_caps;
	tb_transport_message_buffer_t _Nullable transport_buffer;
} __TB_WARN_UNUSED_RESULT;

/// Initialize the members of a structure to 0 or default values.
///
/// @param msg
/// The message to initialize.
TB_EXPORT
void
tb_message_initialize(tb_message_t msg);

/// Copy an existing buffer into the target message.
///
/// @param msg
/// The target message to copy the buffer into.
///
/// @param buffer
/// A pointer to the start of the buffer to copy.
///
/// @param length
/// The number of bytes to copy from the target buffer.
TB_EXPORT
void
tb_message_encode_buffer(tb_message_t msg,
        const void * __sized_by(length) buffer, size_t length);

/// Construct a Tightbeam message.
///
/// @param msg
/// A pointer to an existing message structure to be initialized.
///
/// @param transport_buffer
/// A pointer to the transport buffer that the message should wrap.
///
/// @param disposition
/// The disposition of the message.
///
/// @return An error if the message construction failed, or success.
TB_EXPORT
tb_error_t
tb_message_construct(tb_message_t msg,
		tb_transport_message_buffer_t transport_buffer,
		tb_message_disposition_t disposition);

/// Reset a message back to its initial state.
///
/// @param message
/// The message to reset.
///
/// @param disposition
/// The disposition of the message.
///
/// @param capabilities
/// The number of capabilites that will be encoded.
///
TB_EXPORT
tb_error_t
tb_message_reset(tb_message_t message, tb_message_disposition_t disposition,
		size_t capabilities);

/// Destruct an unwanted unsent or received message and release the space
/// reserved for it in the preallocated Tightbeam message buffer.
///
/// If a completed or partially completed message will not be sent, or a
/// received message will not be fully consumed, call this method to release
/// all the resources associated with it.
///
/// @param msg
/// (in/out) pointer to message metadata to operate on, contents will be
/// uninitialized after this method returns.
TB_EXPORT
void
tb_message_destruct(tb_message_t msg);

TB_EXPORT
void
tb_message_configure_recieved(tb_message_t msg,
                              tb_message_disposition_t disposition);
        // TODO(Sachit): Add the following:
        // TB_DEPRECATED("Please use tb_message_configure_received")

/// Configure an existing `tb_message_t`to be in a received state. This will
/// reset the message state and disposition. Any other pointers, such as that
/// to the transport buffer, will be untouched.
///
/// @param msg
/// The message to be configured.
///
/// @param disposition
/// The disposition of the received message, this must be either
/// TB_MESSAGE_DISPOSITION_REPLY  or TB_MESSAGE_DISPOSITION_QUERY.
TB_EXPORT
void
tb_message_configure_received(tb_message_t msg,
        tb_message_disposition_t disposition);

/// Set the state of a message.
///
/// @param state
/// The new state to set.
TB_EXPORT
void
tb_message_set_state(tb_message_t msg, tb_message_state_t state);

/// Set the disposition of a message.
///
/// @param disposition
/// The new disposition.
TB_EXPORT
void
tb_message_set_disposition(tb_message_t msg,
		tb_message_disposition_t disposition);

/// Get a pointer to the transport buffer stored in a message.
///
/// @param msg The message to fetch the transport buffer for.
///
/// @return
/// A pointer to the transport buffer stored in the provided message.
TB_EXPORT
tb_transport_message_buffer_t _Nullable
tb_message_get_transport_buffer(tb_message_t msg);

/// Set a message buffer in the target message. This must be handled carefully
/// as it can leak the existing transport buffer.
///
/// @param msg
/// The message to set the transport buffer in.
///
/// @param buffer
/// The transport message buffer to set.
TB_EXPORT
void
tb_message_set_transport_buffer(tb_message_t msg,
        tb_transport_message_buffer_t _Nullable buffer);

// NOTE(mww): These methods should be ported to use the platform intrinsics
// client identifier type when available.

/// Get the client identifier for this message
///
/// @param msg The message to fetch the client identifier for.
///
/// @return
/// A client identifier
///
/// @note
/// This method will abort unless the message was TB_MESSAGE_DISPOSITION_QUERY
TB_EXPORT
uint64_t
tb_message_get_client_identifier(tb_message_t msg);

/// Set the client identifier for this message
///
/// @param msg The message to set the client identifier for.
/// @param client_id A client identifier.
///
/// @note
/// This method will abort unless the message was TB_MESSAGE_DISPOSITION_QUERY
TB_EXPORT
void
tb_message_set_client_identifier(tb_message_t msg, uint64_t client_id);

/// Set the connection identifier for this message
///
/// @param msg The message to set the connection identifier of
///
/// @param connection_id The opaque connection identifier value
TB_EXPORT
void
tb_message_set_connection_identifier(tb_message_t msg,
        uintptr_t connection_id);

/// Validate the connection identifier for this message
///
/// @param msg The message to check
///
/// @param connection_id The opaque connection identifier value
///
/// @return Whether the message is valid for the specified connection
///
/// @note This is used to validate that a message is sendable
TB_EXPORT
bool
tb_message_check_connection_identifier(tb_message_t msg,
        uintptr_t connection_id);

/// Reset the connection identifier for this message
///
/// @param msg The message to reset
///
/// @note Indicates the message is not sendable until it's (re)initialized
TB_EXPORT
void
tb_message_clear_connection_identifier(tb_message_t msg);

TB_EXPORT
tb_message_identifier_t
tb_message_get_msg_identifier(tb_message_t msg);

TB_EXPORT
void
tb_message_set_msg_identifier(tb_message_t msg,
        tb_message_identifier_t message_id);

/// Get the number of capabilities in a message.
///
/// @param msg
/// The message to get the number of capabilities in.
///
/// @return
/// The number of capabilities encoded in the message.
TB_EXPORT
size_t
tb_message_get_num_caps(tb_message_t msg);

/// Get the capability at the provided index from the message.
///
/// @param msg
/// The message to get the capability from.
///
/// @param index
/// The index of the capability.
///
/// @return
/// Either a capability or 0.
TB_EXPORT
uint64_t
tb_message_get_capability(tb_message_t msg, size_t index);

/// Check if a flag is set in a message.
///
/// @param message
/// The message to check.
///
/// @param flag
/// The flag to check for.
///
/// @returns true if the flag is set, otherwise false.
TB_EXPORT
bool
tb_message_check_flag(tb_message_t message, tb_transport_flags_t flag);

/// Set the position variable in a message.
///
/// @param message
/// The message to set the position in.
///
/// @param position
/// The position to set.
TB_EXPORT
void
tb_message_set_position(tb_message_t message, size_t position);

__TB_END_DECLS
TB_ASSUME_NONNULL_END

#endif // __TIGHTBEAM_MESSAGE_PRIVATE_H
