/*
 * Copyright (c) 2019 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#ifndef ZEPHYR_LOG_BACKEND_STD_H_
#define ZEPHYR_LOG_BACKEND_STD_H_

#include <logging/log_msg.h>
#include <logging/log_output.h>
#include <kernel.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Logger backend interface for forwarding to standard backend
 * @defgroup log_backend_std Logger backend standard interface
 * @ingroup logger
 * @{
 */

static inline uint32_t log_backend_std_get_flags(void)
{
	uint32_t flags = (LOG_OUTPUT_FLAG_LEVEL | LOG_OUTPUT_FLAG_TIMESTAMP);

	if (IS_ENABLED(CONFIG_LOG_BACKEND_SHOW_COLOR)) {
		flags |= LOG_OUTPUT_FLAG_COLORS;
	}

	if (IS_ENABLED(CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP)) {
		flags |= LOG_OUTPUT_FLAG_FORMAT_TIMESTAMP;
	}

	return flags;
}

/** @brief Put log message to a standard logger backend.
 *
 * @param output	Log output instance.
 * @param flags		Formatting flags.
 * @param msg		Log message.
 */
static inline void
log_backend_std_put(const struct log_output *const output, uint32_t flags,
		    struct log_msg *msg)
{
	log_msg_get(msg);

	flags |= log_backend_std_get_flags();

	log_output_msg_process(output, msg, flags);

	log_msg_put(msg);
}

/** @brief Put a standard logger backend into panic mode.
 *
 * @param output	Log output instance.
 */
static inline void
log_backend_std_panic(const struct log_output *const output)
{
	log_output_flush(output);
}

/** @brief Report dropped messages to a standard logger backend.
 *
 * @param output	Log output instance.
 * @param cnt		Number of dropped messages.
 */
static inline void
log_backend_std_dropped(const struct log_output *const output, uint32_t cnt)
{
	log_output_dropped_process(output, cnt);
}

/** @brief Synchronously process log message by a standard logger backend.
 *
 * @param output	Log output instance.
 * @param flags		Formatting flags.
 * @param src_level	Log message source and level.
 * @param timestamp	Timestamp.
 * @param fmt		Log string.
 * @param ap		Log string arguments.
 */
static inline void
log_backend_std_sync_string(const struct log_output *const output,
			    uint32_t flags, struct log_msg_ids src_level,
			    uint32_t timestamp, const char *fmt, va_list ap)
{
	int key;

	flags |= LOG_OUTPUT_FLAG_LEVEL | LOG_OUTPUT_FLAG_TIMESTAMP;
	if (IS_ENABLED(CONFIG_LOG_BACKEND_SHOW_COLOR)) {
		flags |= LOG_OUTPUT_FLAG_COLORS;
	}

	if (IS_ENABLED(CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP)) {
		flags |= LOG_OUTPUT_FLAG_FORMAT_TIMESTAMP;
	}

	if (IS_ENABLED(CONFIG_LOG_IMMEDIATE) &&
		IS_ENABLED(CONFIG_LOG_IMMEDIATE_CLEAN_OUTPUT)) {
		/* In order to ensure that one log processing is not interrupted
		 * by another one, lock context for whole log processing.
		 */
		key = irq_lock();
	}

	log_output_string(output, src_level, timestamp, fmt, ap, flags);

	if (IS_ENABLED(CONFIG_LOG_IMMEDIATE) &&
		IS_ENABLED(CONFIG_LOG_IMMEDIATE_CLEAN_OUTPUT)) {
		irq_unlock(key);
	}
}

/** @brief Synchronously process hexdump message by a standard logger backend.
 *
 * @param output	Log output instance.
 * @param flags		Formatting flags.
 * @param src_level	Log message source and level.
 * @param timestamp	Timestamp.
 * @param metadata	String associated with a hexdump.
 * @param data		Buffer to dump.
 * @param length	Length of the buffer.
 */
static inline void
log_backend_std_sync_hexdump(const struct log_output *const output,
			     uint32_t flags, struct log_msg_ids src_level,
			     uint32_t timestamp, const char *metadata,
			     const uint8_t *data, uint32_t length)
{
	int key;

	flags |= LOG_OUTPUT_FLAG_LEVEL | LOG_OUTPUT_FLAG_TIMESTAMP;
	if (IS_ENABLED(CONFIG_LOG_BACKEND_SHOW_COLOR)) {
		flags |= LOG_OUTPUT_FLAG_COLORS;
	}

	if (IS_ENABLED(CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP)) {
		flags |= LOG_OUTPUT_FLAG_FORMAT_TIMESTAMP;
	}

	if (IS_ENABLED(CONFIG_LOG_IMMEDIATE) &&
		IS_ENABLED(CONFIG_LOG_IMMEDIATE_CLEAN_OUTPUT)) {
		/* In order to ensure that one log processing is not interrupted
		 * by another one, lock context for whole log processing.
		 */
		key = irq_lock();
	}

	log_output_hexdump(output, src_level, timestamp,
			metadata, data, length, flags);

	if (IS_ENABLED(CONFIG_LOG_IMMEDIATE) &&
		IS_ENABLED(CONFIG_LOG_IMMEDIATE_CLEAN_OUTPUT)) {
		irq_unlock(key);
	}
}

/**
 * @}
 */

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_LOG_BACKEND_STD_H_ */
