//  Copyright (c) 2014 Jakub Filipowicz <jakubf@gmail.com>
//
//  This program 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 program 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 program; if not, write to the Free Software
//  Foundation, Inc.,
//  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#ifndef LOG_H
#define LOG_H

#define _WITH_DPRINTF
#include <stdio.h>
#include <stdarg.h>
#include <inttypes.h>
#include <stdatomic.h>
#include <ctype.h>

#include "libem400.h"

#ifdef __cplusplus
extern "C" {
#endif

extern atomic_uint log_components_enabled;

int log_init(const char *cfg_log_file_name, em400_log_buf_type_t log_buf_type);
void log_shutdown();

int log_enable();
void log_disable();
int log_reopen(const char *file, em400_log_buf_type_t log_buf_type);
unsigned log_is_enabled();

void log_component_enable(unsigned component);
void log_component_disable(unsigned component);
unsigned log_component_get(unsigned component);
int log_setup_components(const char *components);

const char * log_get_component_name(unsigned component);
int log_get_component_id(const char *name);

int log_err(const char *func, const char *msgfmt, ...);
int log_warn(const char *func, const char *msgfmt, ...);
void log_msg_va(em400_sev_t sev, const char *func, const char *fmt, va_list vl);
void log_set_msg_sink(em400_msg_sink_f sink);
void log_log(unsigned component, const char *func, const char *format, ...);
void log_log_va(unsigned component, const char *func, const char *format, va_list args);
void log_splitlog(unsigned component, const char *func, const char *text);

void log_store_cycle_state(uint16_t sr, uint16_t ic);
void log_intlevel_reset();
void log_intlevel_dec();
void log_intlevel_inc();

void log_dasm(int arg, int16_t n, const char *comment);
void log_cpu(unsigned component, const char *msgfmt, ...);

#define LOG_ENABLED atomic_load_explicit(&log_components_enabled, memory_order_relaxed)
#define LOG_WANTS(component) (LOG_ENABLED & (1 << (component)))

#define LOG(component, format, ...) \
	if (LOG_WANTS(component)) log_log(component, __func__, format, ##__VA_ARGS__)
#define LOGCPU(component, format, ...) \
	if (LOG_WANTS(component)) log_cpu(component, format, ##__VA_ARGS__)
#define LOGERR(format, ...) log_err(__func__, format, ##__VA_ARGS__)
#define LOGWARN(format, ...) log_warn(__func__, format, ##__VA_ARGS__)
#define LOGBLOB(component, txt) \
	if (LOG_WANTS(component)) log_splitlog(component, __func__, txt)
#define LOGCHAR(component, format, str, ch) \
	if (isprint(ch)) { LOG(component, format "'%c'", str, ch); } \
	else { LOG(component, format "#%02x", str, ch); }
#define LOGDASM(arg, ac, comment) \
	if (LOG_WANTS(L_CPU)) log_dasm(arg, ac, comment);

#ifdef __cplusplus
}
#endif

#endif

// vim: tabstop=4 shiftwidth=4 autoindent
