// -------------------------------------------------------------------------------------------
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// This file is part of the AWS CDI-SDK, licensed under the BSD 2-Clause "Simplified" License.
// License details at: https://github.com/aws/aws-cdi-sdk/blob/mainline/LICENSE
// -------------------------------------------------------------------------------------------

#ifndef CDI_LOG_API_H__
#define CDI_LOG_API_H__

/**
 * @file
 * @brief
 * This file declares the public API data types, structures and functions that comprise the CDI log API.
 */

// Doxygen for CDI-LOG
/** @page Log_home_page CDI Log (CDI-LOG) API Home Page
 * @tableofcontents
 *
 * @section Log_arch CDI-LOG Architecture
 */

#include "cdi_core_api.h"
#include "cdi_log_enums.h"

#include <stdarg.h>
#include <stdbool.h>

//*********************************************************************************************************************
//***************************************** START OF DEFINITIONS AND TYPES ********************************************
//*********************************************************************************************************************

// Forward references
/// @brief Forward declaration to create pointer to callback parameter when used.
typedef void* CdiUserCbParameter;
/// @brief Forward declaration to create pointer to log message callback data when used.
typedef struct CdiLogMessageCbData CdiLogMessageCbData;
/// @brief Forward declaration to create pointer to callback function when used.
typedef void (*CdiLogMessageCallback)(const CdiLogMessageCbData* cb_data_ptr);
/// @brief Forward declaration to create pointer to connection when used.
typedef struct CdiConnectionState* CdiConnectionHandle;
/// @brief Forward declaration to create pointer to log handle.
typedef struct CdiLogState* CdiLogHandle;

/// @brief Forward declaration to create pointer to callback data when used.
typedef struct CdiLogCallbackData CdiLogCallbackData;
/**
 * @brief This defines a structure that contains the information used to configure a callback log, referred to using the
 *        enumerated value kLogMethodCallback.
 */
struct CdiLogCallbackData {
    /// @brief Address to user defined log message callback function.
    CdiLogMessageCallback log_msg_cb_ptr;
    /// @brief User defined callback parameter that is passed to the user defined log message callback function. This
    /// allows the application to associate a log message with the global log or a specific connection.
    CdiUserCbParameter log_user_cb_param;
};

/// @brief Forward declaration to create pointer to method data when used.
typedef struct CdiLogMethodData CdiLogMethodData;
/**
 * @brief A structure of this type is used to configure the type of log method that is being used. It is passed as the
 *        parameter to CdiCoreInitialize() and as part of the CdiTxConfigData or CdiRxConfigData configuration data
 *        passed to the Cdi...TxCreate() API functions.
 */
struct CdiLogMethodData {
    /// @brief Indicates which structure of the union is valid.
    CdiLogMethod log_method;
    union {
        /// @brief The internal state of the structure contains no data if log_method is kLogMethodStdout.

        /// @brief The internal state of the structure if log_method is kLogMethodCallback.
        CdiLogCallbackData callback_data;
        /// @brief The internal state of the structure if log_method is kLogMethodFile.
        const char* log_filename_str;
    };
};

typedef struct CdiLogMessageCbData CdiLogMessageCbData;
/**
 * @brief A structure of this type is passed as the parameter to CdiLogMessageCallback(). It contains a single log
 *        message generated by the SDK.
 */
struct CdiLogMessageCbData {
    /// @brief The handle of the connection which generated the log message. It is the instance which was created using
    ///        a previous call to one of the Cdi...Create() API functions. If NULL, then the global logger generated the
    ///        log message.
    CdiConnectionHandle connection_handle;

    /// @brief If connection_handle is not NULL, this is the user defined log message callback parameter that was
    /// specified when the connection instance was created using one of the Cdi...Create() API functions. If
    /// connection_handle is NULL, then the global logger generated the log message and this value should be ignored.
    CdiUserCbParameter log_user_cb_param;

    /// @brief Type of component that generated the message.
    CdiLogComponent component;

    /// @brief Level of the log message.
    CdiLogLevel log_level;

    /// @brief Pointer to string containing the name of the function the message was generated from.
    const char* source_code_function_name_ptr;
    /// @brief Source code line number that message was generated from.
    int source_code_line_number;

    /// @brief For a single-line log message, contains 1. Otherwise, contains the number of lines in a multiline
    /// message.
    int line_count;

    /// @brief Pointer to message string. If the message contains multiple lines, each line is terminated with a '\0'.
    const char* message_str;
};

/**
 * @brief Prototype of log message callback function. The user code can optionally implement a function with this
 * prototype, and provide it as part of the CdiTxConfigData or CdiRxConfigData that is passed to one of the
 * Cdi...Create() functions.
 *
 * This callback function is invoked whenever a log message is generated. Control of which log components are enabled
 * is set using CdiCoreLogComponentEnable(). Log levels are set using CdiCoreLogLevelSet().
 *
 * @param cb_data_ptr A pointer to an CdiLogMessageCbData structure.
 */
typedef void (*CdiLogMessageCallback)(const CdiLogMessageCbData* cb_data_ptr);

//*********************************************************************************************************************
//******************************************* START OF PUBLIC FUNCTIONS ***********************************************
//*********************************************************************************************************************

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Enable or disable specific log component messages for a specific connection or the global logger. All components are
 * disabled by default.
 *
 * @param handle Connection handle returned by Cdi...TxCreate() API functions. If NULL, then the global logger is used.
 * @param component Type of component to enable/disable log message generation.
 * @param enable True to enable, False to disable.
 *
 * @return A value from the CdiReturnStatus enumeration.
 */
CDI_INTERFACE CdiReturnStatus CdiLogComponentEnable(CdiConnectionHandle handle, CdiLogComponent component, bool enable);

/**
 * Enable or disable specific log component messages globally for all logs. All components are disabled by default.
 *
 * @param component Type of component to enable/disable log message generation.
 * @param enable To enable use true, otherwise use false.
 *
 * @return A value from the CdiReturnStatus enumeration.
 */
CDI_INTERFACE CdiReturnStatus CdiLogComponentEnableGlobal(CdiLogComponent component, bool enable);

/**
 * Determine if a component is enabled for logging for a specific connection or the global logger.
 *
 * @param handle Connection handle returned by Cdi...TxCreate() API functions. If NULL, then the global logger is used.
 * @param component Type of component to check.
 *
 * @return True if enabled, otherwise false.
 */
CDI_INTERFACE bool CdiLogComponentIsEnabled(CdiConnectionHandle handle, CdiLogComponent component);

/**
 * Set log level for a component for a specific connection or the global logger. Log messages of the specified level or
 * lower are generated. The default log level is set to kLogInfo.
 *
 * @param handle Connection handle returned by Cdi...TxCreate() API functions. If NULL, then the global logger is used.
 * @param component Type of component to set log level.
 * @param level Log level to set.
 *
 * @return A value from the CdiReturnStatus enumeration.
 */
CDI_INTERFACE CdiReturnStatus CdiLogLevelSet(CdiConnectionHandle handle, CdiLogComponent component, CdiLogLevel level);

/**
 * Set log level for a component for all logs. Log messages of the specified level or lower are generated. The default
 * log level is set to kLogInfo.
 *
 * @param component Type of component to set log level.
 * @param level Log level to set.
 *
 * @return A value from the CdiReturnStatus enumeration.
 */
CDI_INTERFACE CdiReturnStatus CdiLogLevelSetGlobal(CdiLogComponent component, CdiLogLevel level);

/**
 * Send log messages to stderr in addition to log files, if log files are enabled.
 *
 * @param enable Use true to enable, false to disable.
 * @param level Log level to enable output to stderr.
 *
 * @return A value from the CdiReturnStatus enumeration.
 */
CDI_INTERFACE CdiReturnStatus CdiLogStderrEnable(bool enable, CdiLogLevel level);

/**
 * Get the handle to the global log set by the CdiCoreInitialize() API.
 *
 * @return Handle of global log. If the CdiCoreInitialize() API has not been used, NULL is returned.
 */
CDI_INTERFACE CdiLogHandle CdiLogGlobalGet(void);

#ifdef __cplusplus
}
#endif

#endif // CDI_LOG_API_H__

