//
//  tb_connection_private.h
//  Tightbeam

#ifndef __TIGHTBEAM_CONNECTION_PRIVATE_H
#define __TIGHTBEAM_CONNECTION_PRIVATE_H

#include <Tightbeam/tb_connection.h>
#include <Tightbeam/tb_connection_observers.h>
#include <Tightbeam/tb_list.h>

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

TB_ASSUME_NONNULL_BEGIN
__TB_BEGIN_DECLS

typedef struct _tb_connection_s {
    // A structure defining the underlying transport.
    tb_transport_t transport;
    
    _tb_connection_observers_table_t observers;

    tb_connection_message_handler_b message_handler_b;
    tb_connection_message_handler_f message_handler_f;
    void *message_handler_context;

    // The context associated with this Tightbeam connection.
    // The connection context is owned by the caller.
    void *context;

#if defined(__RTKIT__) && defined(__ILP32__)
    // RTKit builds for 32-bit platforms and the padding here
    // must account for the decreased size of pointer sized
    // fields in this structure.
    uint64_t _pad[1];
#endif // defined(__RTKIT__) && defined(__ILP32__)

#if !defined(__RTKIT__) && !defined(__AFK__)
    // A list that contains parts of multi-part messages currently being
    // accumulated -- Unsupported in RTKit environments.
    tb_list_t accumulator_list;
    tb_list_t reply_list;
#endif // !TARGET_RTKIT
} _tb_connection_s, *_tb_connection_t __TB_WARN_UNUSED_RESULT;

_Static_assert(sizeof(struct tb_connection_s) >= sizeof(struct _tb_connection_s), "");

TB_ENUM(tb_connection_type, uint8_t,
    TB_CONNECTION_TYPE_CLIENT TB_SWIFT_NAME(client) = 0,
    TB_CONNECTION_TYPE_SERVICE TB_SWIFT_NAME(service),
) TB_SWIFT_NAME(ConnectionType);

/// Reset a message back to an initial state. This is so the message can be
/// used as a reply or a new query.
///
/// @param connection
/// The connection that will be used to send the message.
///
/// @param msg
/// The message to reset.
///
/// @param type
/// The connection type, which determines the message disposition to set.
///
/// @param bytes
/// The number of bytes to reserve in the message payload. This should NOT
/// include any preamble size.
///
/// @param capabilities
/// The number of capabilities that will be encoded.
TB_EXPORT
tb_error_t
_tb_message_reset(struct tb_connection_s *connection,
        tb_message_t msg, tb_connection_type_t type, size_t bytes,
        size_t capabilities);

/// Reset a transport buffer back to an initial state. This is to be used by
/// layers of the system that don't have access to the message that contains
/// the transport buffer and should be used carefully. The owning message's
/// state must be modified manually.
///
/// @param transport
/// The transport that will be used to send the message.
///
/// @param transport_buffer
/// The transport buffer to reset.
///
/// @param bytes
/// The new size to reset the transport buffer with.
///
/// @param capabilities
/// The number of capabilities the new buffer will hold.
TB_EXPORT
tb_error_t
_tb_message_buffer_reset(struct tb_connection_s *conn, tb_transport_t transport,
        tb_transport_message_buffer_t transport_buffer, size_t bytes,
        size_t capabilities);

/// Get a pointer to the transport underneath a connection.
///
/// @param connection
/// The connection struct to find the transport for.
///
/// @return
/// A pointer to the transport that the connection wraps.
TB_EXPORT
tb_transport_t _Nullable
tb_connection_get_transport(struct tb_connection_s * _Nonnull connection);

TB_EXPORT
void
_tb_connection_init_observers(struct tb_connection_s *conn);

TB_EXPORT
_Nullable _tb_connection_observers_table_t
_tb_connection_get_observers(struct tb_connection_s *conn);

TB_EXPORT
void
_tb_connection_clear_observers(struct tb_connection_s *conn);

TB_EXPORT
void 
_tb_connection_observe_send_message(struct tb_connection_s *conn,
        tb_transport_t transport, tb_message_t query,
        tb_message_t _Nonnull * _Nullable response,
        tb_connection_flags_t flags);

TB_EXPORT
void
_tb_connection_observe_activate_service(struct tb_connection_s *conn,
        tb_transport_t transport);

TB_EXPORT
void
_tb_connection_observe_activate_client(struct tb_connection_s *conn,
        tb_transport_t transport);

TB_EXPORT
void
_tb_connection_observe_reset_message(struct tb_connection_s *conn,
            tb_transport_t transport, tb_transport_message_buffer_t msg_buffer,
            size_t capabilities, size_t bytes);

TB_EXPORT
void
_tb_connection_observe_message_handler(struct tb_connection_s *conn,
        tb_message_t message);

/// Allocate a payload for and initialize a _connection-owned_ transport
/// message buffer structure.
///
/// @param size
/// The size of the payload to allocate.
///
/// @param transport_buffer
/// The transport buffer to initialize.
///
/// @return
/// Success or an error on failure.
TB_EXPORT
tb_error_t
tb_connection_alloc_init_owned_transport_message_buffer(
        tb_transport_message_buffer_t transport_buffer, size_t size);

/// Deallocate the payload inside a _connection-owned_ transport and destruct
/// the message buffer structure.
///
/// @param transport_buffer
/// The transport buffer to dealloc the payload from and destruct.
TB_EXPORT
void
tb_connection_dealloc_destruct_owned_transport_message_buffer(
        tb_transport_message_buffer_t transport_buffer);

__TB_END_DECLS
TB_ASSUME_NONNULL_END

#endif // __TIGHTBEAM_CONNECTION_PRIVATE_H
